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/tools | |
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/tools')
-rw-r--r-- | base/tps/tools/CMakeLists.txt | 1 | ||||
-rw-r--r-- | base/tps/tools/raclient/CMakeLists.txt | 47 | ||||
-rw-r--r-- | base/tps/tools/raclient/RA_Client.cpp | 1645 | ||||
-rw-r--r-- | base/tps/tools/raclient/RA_Client.h | 78 | ||||
-rw-r--r-- | base/tps/tools/raclient/RA_Conn.cpp | 1037 | ||||
-rw-r--r-- | base/tps/tools/raclient/RA_Conn.h | 71 | ||||
-rw-r--r-- | base/tps/tools/raclient/RA_Token.cpp | 2008 | ||||
-rw-r--r-- | base/tps/tools/raclient/RA_Token.h | 225 | ||||
-rw-r--r-- | base/tps/tools/raclient/enroll.tps | 42 | ||||
-rw-r--r-- | base/tps/tools/raclient/enroll1.test | 43 | ||||
-rw-r--r-- | base/tps/tools/raclient/format.tps | 45 | ||||
-rw-r--r-- | base/tps/tools/raclient/nt_enroll.test | 212 | ||||
-rw-r--r-- | base/tps/tools/raclient/readme.txt | 247 | ||||
-rw-r--r-- | base/tps/tools/raclient/reset_pin.tps | 42 | ||||
-rw-r--r-- | base/tps/tools/raclient/reset_pin1.test | 40 | ||||
-rw-r--r-- | base/tps/tools/raclient/reset_pin2.test | 39 | ||||
-rw-r--r-- | base/tps/tools/tus/add.c | 117 | ||||
-rw-r--r-- | base/tps/tools/tus/test.c | 117 |
18 files changed, 6056 insertions, 0 deletions
diff --git a/base/tps/tools/CMakeLists.txt b/base/tps/tools/CMakeLists.txt new file mode 100644 index 000000000..6ed05c43d --- /dev/null +++ b/base/tps/tools/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(raclient) diff --git a/base/tps/tools/raclient/CMakeLists.txt b/base/tps/tools/raclient/CMakeLists.txt new file mode 100644 index 000000000..8f01b34d8 --- /dev/null +++ b/base/tps/tools/raclient/CMakeLists.txt @@ -0,0 +1,47 @@ +project(tpsclient CXX) + +set(TPS_PRIVATE_INCLUDE_DIRS + ${TPS_PUBLIC_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} +) + +set(TPS_EXECUTABLE + tpsclient + CACHE INTERNAL "tpsclient executable" +) + +set(TPS_LINK_LIBRARIES + ${TPS_SHARED_LIBRARY} + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} +) + +set(tpsclient_SRCS + RA_Client.cpp + RA_Conn.cpp + RA_Token.cpp +) + +include_directories(${TPS_PRIVATE_INCLUDE_DIRS}) + +add_executable(${TPS_EXECUTABLE} ${tpsclient_SRCS}) +target_link_libraries(${TPS_EXECUTABLE} ${TPS_LINK_LIBRARIES}) + +install( + TARGETS + ${TPS_EXECUTABLE} + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR}/tps + ARCHIVE DESTINATION ${LIB_INSTALL_DIR}/tps +) + +install( + FILES + enroll.tps + format.tps + reset_pin.tps + DESTINATION + ${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}/tps/samples +) diff --git a/base/tps/tools/raclient/RA_Client.cpp b/base/tps/tools/raclient/RA_Client.cpp new file mode 100644 index 000000000..c2a610e33 --- /dev/null +++ b/base/tps/tools/raclient/RA_Client.cpp @@ -0,0 +1,1645 @@ +// --- 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 <string.h> +#include <stdarg.h> +#include "prinrval.h" + +#include "prmem.h" +#include "prsystem.h" +#include "plstr.h" +#include "prio.h" +#include "prprf.h" +#include "pk11func.h" + +#include "main/NameValueSet.h" +#include "main/Util.h" +#include "main/RA_Msg.h" +#include "authentication/AuthParams.h" +#include "apdu/APDU_Response.h" +#include "apdu/Initialize_Update_APDU.h" +#include "apdu/External_Authenticate_APDU.h" +#include "apdu/Set_Pin_APDU.h" +#include "msg/RA_Begin_Op_Msg.h" +#include "msg/RA_End_Op_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_Token_PDU_Request_Msg.h" +#include "msg/RA_Token_PDU_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_ASQ_Request_Msg.h" +#include "msg/RA_ASQ_Response_Msg.h" +#include "msg/RA_Status_Update_Request_Msg.h" +#include "msg/RA_Status_Update_Response_Msg.h" +#include "RA_Token.h" +#include "RA_Client.h" + +#include "nss.h" + +static PRFileDesc *m_fd_debug = (PRFileDesc *) NULL; +PRBool old_style = PR_TRUE; + +/** + * Constructs a RA client that talks to RA. + */ +RA_Client::RA_Client () +{ + /* default global variables */ + m_vars.Add ("ra_host", "air"); + m_vars.Add ("ra_port", "8000"); + m_vars.Add ("ra_uri", "/nk_service"); +} + +/** + * Destructs this RA client. + */ +RA_Client::~RA_Client () +{ + if (m_fd_debug != NULL) + { + PR_Close (m_fd_debug); + m_fd_debug = NULL; + } +} + +static void +PrintHeader () +{ + printf ("Registration Authority Client\n"); + printf ("'op=help' for Help\n"); +} + +static void +Output (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + printf ("Output> "); + vprintf (fmt, ap); + printf ("\n"); + va_end (ap); +} + +static void +PrintPrompt () +{ + printf ("Command>"); +} + +static void +OutputSuccess (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + printf ("Result> Success - "); + vprintf (fmt, ap); + printf ("\n"); + va_end (ap); +} + +static void +OutputError (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + printf ("Result> Error - "); + vprintf (fmt, ap); + printf ("\n"); + va_end (ap); +} + +static int +ReadLine (char *buf, int len) +{ + char *cur = buf; + + while (1) + { + *cur = getchar (); + if (*cur == '\r') + { + continue; + } + if (*cur == '\n') + { + *cur = '\0'; + return 1; + } + cur++; + } + return 0; +} + +void +RA_Client::Debug (const char *func_name, const char *fmt, ...) +{ + PRTime now; + const char *time_fmt = "%Y-%m-%d %H:%M:%S"; + char datetime[1024]; + PRExplodedTime time; + + if (m_fd_debug == NULL) + return; + va_list ap; + va_start (ap, fmt); + now = PR_Now (); + PR_ExplodeTime (now, PR_LocalTimeParameters, &time); + PR_FormatTimeUSEnglish (datetime, 1024, time_fmt, &time); + PR_fprintf (m_fd_debug, "[%s] %s - ", datetime, func_name); + PR_vfprintf (m_fd_debug, fmt, ap); + va_end (ap); + PR_Write (m_fd_debug, "\n", 1); +} + +int +RA_Client::OpHelp (NameValueSet * params) +{ + Output ("Available Operations:"); + Output ("op=debug filename=<filename> - enable debugging"); + Output ("op=help"); + Output + ("op=ra_enroll uid=<uid> pwd=<pwd> num_threads=<number of threads> secureid_pin=<secureid_pin> keygen=<true|false> - Enrollment Via RA"); + Output + ("op=ra_reset_pin uid=<uid> pwd=<pwd> num_threads=<number of threads> secureid_pin=<secureid_pin> new_pin=<new_pin> - Reset Pin Via RA"); + Output + ("op=ra_update uid=<uid> pwd=<pwd> num_threads=<number of threads> secureid_pin=<secureid_pin> new_pin=<new_pin> - Reset Pin Via RA"); + Output ("op=token_set <name>=<value> - Set Token Value"); + Output ("op=token_status - Print Token Status"); + Output ("op=var_get name=<name> - Get Value of Variable"); + Output ("op=var_list - List All Variables"); + Output ("op=var_set name=<name> value=<value> - Set Value to Variable"); + + return 1; +} + +static void +GetBuffer (Buffer & buf, char *output, int len) +{ + int i; + + output[0] = '\0'; + for (i = 0; i < (int) buf.size (); ++i) + { + sprintf (output, "%s%02x", output, ((BYTE *) buf)[i]); + } +} + +static BYTE +ToVal (char c) +{ + if (c >= '0' && c <= '9') + { + return c - '0'; + } + else if (c >= 'A' && c <= 'Z') + { + return c - 'A' + 10; + } + else if (c >= 'a' && c <= 'z') + { + return c - 'a' + 10; + } + + /* The following return is needed to suppress compiler warnings on Linux. */ + return 0; +} + +static Buffer * +ToBuffer (char *input) +{ + int len = strlen (input) / 2; + BYTE *buffer = NULL; + + buffer = (BYTE *) malloc (len); + if (buffer == NULL) + { + return NULL; + } + + for (int i = 0; i < len; i++) + { + buffer[i] = (ToVal (input[i * 2]) * 16) + ToVal (input[i * 2 + 1]); + } + Buffer *j; + j = new Buffer (buffer, len); + + if (buffer != NULL) + { + free (buffer); + buffer = NULL; + } + + return j; +} + +int +RA_Client::OpTokenStatus (NameValueSet * params) +{ + int i; + char output[2048]; + + Output ("life_cycle_state : '%x'", m_token.GetLifeCycleState ()); + Output ("pin : '%s'", m_token.GetPIN ()); + GetBuffer (m_token.GetAppletVersion (), output, 2048); + Output ("app_ver : '%s' (%d bytes)", output, + m_token.GetAppletVersion ().size ()); + Output ("major_ver : '%x'", m_token.GetMajorVersion ()); + Output ("minor_ver : '%x'", m_token.GetMinorVersion ()); + GetBuffer (m_token.GetCUID (), output, 2048); + Output ("cuid : '%s' (%d bytes)", output, m_token.GetCUID ().size ()); + GetBuffer (m_token.GetMSN (), output, 2048); + Output ("msn : '%s' (%d bytes)", output, m_token.GetMSN ().size ()); + GetBuffer (m_token.GetKeyInfo (), output, 2048); + Output ("key_info : '%s' (%d bytes)", output, + m_token.GetKeyInfo ().size ()); + GetBuffer (m_token.GetAuthKey (), output, 2048); + Output ("auth_key : '%s' (%d bytes)", output, + m_token.GetAuthKey ().size ()); + GetBuffer (m_token.GetMacKey (), output, 2048); + Output ("mac_key : '%s' (%d bytes)", output, m_token.GetMacKey ().size ()); + GetBuffer (m_token.GetKekKey (), output, 2048); + Output ("kek_key : '%s' (%d bytes)", output, m_token.GetKekKey ().size ()); + + /* print all the public/private keys */ + if (params->GetValue ("print_cert") != NULL) + { + for (i = 0; i < m_token.NoOfCertificates (); i++) + { + CERTCertificate *cert = m_token.GetCertificate (i); + Output ("Certificate #%d: '%s'", i, cert->nickname); + } + } + + if (params->GetValue ("print_private") != NULL) + { + for (i = 0; i < m_token.NoOfPrivateKeys (); i++) + { + SECKEYPrivateKey *key = m_token.GetPrivateKey (i); +#if 0 + SECKEYPublicKey *pubKey = SECKEY_ConvertToPublicKey (key); + Buffer modulus = Buffer (pubKey->u.rsa.modulus.data, + pubKey->u.rsa.modulus.len); + Buffer exponent = Buffer (pubKey->u.rsa.publicExponent.data, + pubKey->u.rsa.publicExponent.len); +#endif + Output ("Private Key #%d: '%s'", i, + PK11_GetPrivateKeyNickname (key)); + } + } + + return 1; +} + +int +RA_Client::OpTokenSet (NameValueSet * params) +{ + if (params->GetValue ("cuid") != NULL) + { + Buffer *CUID = ToBuffer (params->GetValue ("cuid")); + m_token.SetCUID (*CUID); + if (CUID != NULL) + { + delete CUID; + CUID = NULL; + } + } + if (params->GetValue ("msn") != NULL) + { + Buffer *MSN = ToBuffer (params->GetValue ("msn")); + m_token.SetMSN (*MSN); + if (MSN != NULL) + { + delete MSN; + MSN = NULL; + } + } + if (params->GetValue ("app_ver") != NULL) + { + Buffer *Version = ToBuffer (params->GetValue ("app_ver")); + m_token.SetAppletVersion (*Version); + if (Version != NULL) + { + delete Version; + Version = NULL; + } + } + if (params->GetValue ("major_ver") != NULL) + { + m_token.SetMajorVersion (atoi (params->GetValue ("major_ver"))); + } + if (params->GetValue ("minor_ver") != NULL) + { + m_token.SetMinorVersion (atoi (params->GetValue ("minor_ver"))); + } + if (params->GetValue ("key_info") != NULL) + { + Buffer *KeyInfo = ToBuffer (params->GetValue ("key_info")); + m_token.SetKeyInfo (*KeyInfo); + if (KeyInfo != NULL) + { + delete KeyInfo; + KeyInfo = NULL; + } + } + if (params->GetValue ("auth_key") != NULL) + { + Buffer *Key = ToBuffer (params->GetValue ("auth_key")); + m_token.SetAuthKey (*Key); + if (Key != NULL) + { + delete Key; + Key = NULL; + } + } + if (params->GetValue ("mac_key") != NULL) + { + Buffer *Key = ToBuffer (params->GetValue ("mac_key")); + m_token.SetMacKey (*Key); + if (Key != NULL) + { + delete Key; + Key = NULL; + } + } + if (params->GetValue ("kek_key") != NULL) + { + Buffer *Key = ToBuffer (params->GetValue ("kek_key")); + m_token.SetKekKey (*Key); + if (Key != NULL) + { + delete Key; + Key = NULL; + } + } + return 1; +} + +static int +HandleStatusUpdateRequest (RA_Client * client, + RA_Status_Update_Request_Msg * req, + RA_Token * token, RA_Conn * conn, + NameValueSet * vars, NameValueSet * params) +{ + client->Debug ("RA_Client::HandleStatusUpdateRequest", + "RA_Client::HandleStatusUpdateRequest"); + RA_Status_Update_Response_Msg resp = + RA_Status_Update_Response_Msg (req->GetStatus ()); + conn->SendMsg (&resp); + return 1; +} + +static int +HandleExtendedLoginRequest (RA_Client * client, + RA_Extended_Login_Request_Msg * req, + RA_Token * token, RA_Conn * conn, + NameValueSet * vars, NameValueSet * params) +{ + client->Debug ("RA_Client::HandleExtendLoginRequest", + "RA_Client::HandleExtendedLoginRequest"); + AuthParams *auths = new AuthParams; + auths->SetUID (params->GetValue ("uid")); + auths->SetPassword (params->GetValue ("pwd")); + if (vars->GetValueAsBool ("test_enable", 0) == 1) + { + if (vars->GetValueAsBool ("test_el_resp_exclude_uid", 0) == 1) + { + auths->Remove ("UID"); + } + if (vars->GetValueAsBool ("test_el_resp_exclude_pwd", 0) == 1) + { + auths->Remove ("PASSWORD"); + } + if (vars->GetValueAsBool ("test_el_resp_include_invalid_param", 0) == 1) + { + auths->Add ("XXX", "YYY"); + } + } + RA_Extended_Login_Response_Msg resp = + RA_Extended_Login_Response_Msg (auths); + conn->SendMsg (&resp); + return 1; +} + +static int +HandleLoginRequest (RA_Client * client, + RA_Login_Request_Msg * req, + RA_Token * token, RA_Conn * conn, + NameValueSet * vars, NameValueSet * params) +{ + client->Debug ("RA_Client::HandleLoginRequest", + "RA_Client::HandleLoginRequest"); + RA_Login_Response_Msg resp = + RA_Login_Response_Msg (params->GetValue ("uid"), + params->GetValue ("pwd")); + conn->SendMsg (&resp); + return 1; +} + +static int +HandleNewPinRequest (RA_Client * client, + RA_New_Pin_Request_Msg * req, + RA_Token * token, RA_Conn * conn, + NameValueSet * vars, NameValueSet * params) +{ + client->Debug ("RA_Client::HandleNewPinRequest", + "RA_Client::HandleNewPinRequest"); + int min_len = req->GetMinLen (); + int max_len = req->GetMaxLen (); + Output ("Min Len: '%d' Max Len: '%d'", min_len, max_len); + RA_New_Pin_Response_Msg resp = + RA_New_Pin_Response_Msg (params->GetValue ("new_pin")); + conn->SendMsg (&resp); + + return 1; +} + +static int +HandleASQRequest (RA_Client * client, + RA_ASQ_Request_Msg * req, + RA_Token * token, RA_Conn * conn, + NameValueSet * vars, NameValueSet * params) +{ + client->Debug ("RA_Client::HandleASQRequest", + "RA_Client::HandleASQRequest"); + Output ("ASQ Question: '%s'", req->GetQuestion ()); + RA_ASQ_Response_Msg resp = + RA_ASQ_Response_Msg (params->GetValue ("answer")); + conn->SendMsg (&resp); + + return 1; +} + +static int +HandleSecureIdRequest (RA_Client * client, + RA_SecureId_Request_Msg * req, + RA_Token * token, RA_Conn * conn, + NameValueSet * vars, NameValueSet * params) +{ + client->Debug ("RA_Client::HandleSecureIdRequest", + "RA_Client::HandleSecureIdRequest"); + int pin_required = req->IsPinRequired (); + int next_value = req->IsNextValue (); + Output ("Pin Required: '%d' Next Value: '%d'", pin_required, next_value); + RA_SecureId_Response_Msg resp = + RA_SecureId_Response_Msg (params->GetValue ("secureid_value"), + params->GetValue ("secureid_pin")); + conn->SendMsg (&resp); + return 1; +} + +static int +HandleTokenPDURequest (RA_Client * client, + RA_Token_PDU_Request_Msg * req, + RA_Token * token, RA_Conn * conn, + NameValueSet * vars, NameValueSet * params) +{ + client->Debug ("RA_Client::HandleTokenPDURequest", + "RA_Client::HandleTokenPDURequest"); + APDU *apdu = req->GetAPDU (); + APDU_Response *apdu_resp = token->Process (apdu, vars, params); + if (apdu_resp == NULL) + { + return 0; + } + RA_Token_PDU_Response_Msg *resp = new RA_Token_PDU_Response_Msg (apdu_resp); + conn->SendMsg (resp); + + if (resp != NULL) + { + delete resp; + resp = NULL; + } + // if( apdu_resp != NULL ) { + // delete apdu_resp; + // apdu_resp = NULL; + // } + + return 1; +} + + +typedef struct _ThreadArg +{ + PRTime time; /* processing time */ + int status; /* status result */ + NameValueSet *params; /* parameters */ + RA_Client *client; /* client */ + RA_Token *token; /* token */ + + PRLock *donelock; /* lock */ + int done; /* are we done? */ +} ThreadArg; + +#ifdef __cplusplus +extern "C" +{ +#endif + + static void ThreadConnUpdate (void *arg) + { + PRTime start, end; + ThreadArg *targ = (ThreadArg *) arg; + + start = PR_Now (); + RA_Conn conn (targ->client->m_vars.GetValue ("ra_host"), + atoi (targ->client->m_vars.GetValue ("ra_port")), + targ->client->m_vars.GetValue ("ra_uri")); + + if (!conn.Connect ()) + { + OutputError ("Cannot connect to %s:%d", + targ->client->m_vars.GetValue ("ra_host"), + atoi (targ->client->m_vars.GetValue ("ra_port"))); + targ->status = 0; + if (!old_style) + { + PR_Lock (targ->donelock); + targ->done = PR_TRUE; + PR_Unlock (targ->donelock); + } + + return; + } + + NameValueSet *exts = NULL; + char *extensions = + targ->params->GetValueAsString ((char *) "extensions", NULL); + if (extensions != NULL) + { + exts = NameValueSet::Parse (extensions, "&"); + } + + RA_Begin_Op_Msg beginOp = RA_Begin_Op_Msg (OP_FORMAT, exts); + conn.SendMsg (&beginOp); + + /* handle secure ID (optional) */ + while (1) + { + RA_Msg *msg = (RA_Msg *) conn.ReadMsg (targ->token); + if (msg == NULL) + break; + if (msg->GetType () == MSG_LOGIN_REQUEST) + { + targ->status = + HandleLoginRequest (targ->client, (RA_Login_Request_Msg *) msg, + targ->token, &conn, &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_EXTENDED_LOGIN_REQUEST) + { + targ->status = + HandleExtendedLoginRequest (targ->client, + (RA_Extended_Login_Request_Msg *) + msg, targ->token, &conn, + &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_STATUS_UPDATE_REQUEST) + { + targ->status = + HandleStatusUpdateRequest (targ->client, + (RA_Status_Update_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, targ->params); + } + else if (msg->GetType () == MSG_SECUREID_REQUEST) + { + targ->status = + HandleSecureIdRequest (targ->client, + (RA_SecureId_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, targ->params); + } + else if (msg->GetType () == MSG_ASQ_REQUEST) + { + targ->status = + HandleASQRequest (targ->client, (RA_ASQ_Request_Msg *) msg, + targ->token, &conn, &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_TOKEN_PDU_REQUEST) + { + targ->status = + HandleTokenPDURequest (targ->client, + (RA_Token_PDU_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, targ->params); + } + else if (msg->GetType () == MSG_NEW_PIN_REQUEST) + { + targ->status = + HandleNewPinRequest (targ->client, + (RA_New_Pin_Request_Msg *) msg, + targ->token, &conn, &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_END_OP) + { + RA_End_Op_Msg *endOp = (RA_End_Op_Msg *) msg; + if (endOp->GetResult () == 0) + { + targ->status = 1; /* error */ + } + else + { + targ->status = 0; + } + if (msg != NULL) + { + delete msg; + msg = NULL; + } + break; + } + else + { + /* error */ + targ->status = 0; + } + if (msg != NULL) + { + delete msg; + msg = NULL; + } + + if (targ->status == 0) + break; + } + + conn.Close (); + end = PR_Now (); + targ->time = (end - start) / 1000; + + if (!old_style) + { + PR_Lock (targ->donelock); + targ->done = PR_TRUE; + PR_Unlock (targ->donelock); + } + } + + static void ThreadConnResetPin (void *arg) + { + PRTime start, end; + ThreadArg *targ = (ThreadArg *) arg; + + start = PR_Now (); + RA_Conn conn (targ->client->m_vars.GetValue ("ra_host"), + atoi (targ->client->m_vars.GetValue ("ra_port")), + targ->client->m_vars.GetValue ("ra_uri")); + + if (!conn.Connect ()) + { + OutputError ("Cannot connect to %s:%d", + targ->client->m_vars.GetValue ("ra_host"), + atoi (targ->client->m_vars.GetValue ("ra_port"))); + targ->status = 0; + + if (!old_style) + { + PR_Lock (targ->donelock); + targ->done = PR_TRUE; + PR_Unlock (targ->donelock); + } + + return; + } + + NameValueSet *exts = NULL; + char *extensions = + targ->params->GetValueAsString ((char *) "extensions", NULL); + if (extensions != NULL) + { + exts = NameValueSet::Parse (extensions, "&"); + } + + RA_Begin_Op_Msg beginOp = RA_Begin_Op_Msg (OP_RESET_PIN, exts); + conn.SendMsg (&beginOp); + + /* handle secure ID (optional) */ + while (1) + { + RA_Msg *msg = (RA_Msg *) conn.ReadMsg (targ->token); + if (msg == NULL) + break; + if (msg->GetType () == MSG_LOGIN_REQUEST) + { + targ->status = + HandleLoginRequest (targ->client, (RA_Login_Request_Msg *) msg, + targ->token, &conn, &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_EXTENDED_LOGIN_REQUEST) + { + targ->status = + HandleExtendedLoginRequest (targ->client, + (RA_Extended_Login_Request_Msg *) + msg, targ->token, &conn, + &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_STATUS_UPDATE_REQUEST) + { + targ->status = + HandleStatusUpdateRequest (targ->client, + (RA_Status_Update_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, targ->params); + } + else if (msg->GetType () == MSG_SECUREID_REQUEST) + { + targ->status = + HandleSecureIdRequest (targ->client, + (RA_SecureId_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, targ->params); + } + else if (msg->GetType () == MSG_ASQ_REQUEST) + { + targ->status = + HandleASQRequest (targ->client, (RA_ASQ_Request_Msg *) msg, + targ->token, &conn, &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_TOKEN_PDU_REQUEST) + { + targ->status = + HandleTokenPDURequest (targ->client, + (RA_Token_PDU_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, targ->params); + } + else if (msg->GetType () == MSG_NEW_PIN_REQUEST) + { + targ->status = + HandleNewPinRequest (targ->client, + (RA_New_Pin_Request_Msg *) msg, + targ->token, &conn, &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_END_OP) + { + RA_End_Op_Msg *endOp = (RA_End_Op_Msg *) msg; + if (endOp->GetResult () == 0) + { + targ->status = 1; /* error */ + } + else + { + targ->status = 0; + } + if (msg != NULL) + { + delete msg; + msg = NULL; + } + break; + } + else + { + /* error */ + targ->status = 0; + } + if (msg != NULL) + { + delete msg; + msg = NULL; + } + + if (targ->status == 0) + break; + } + + conn.Close (); + end = PR_Now (); + targ->time = (end - start) / 1000; + + if (!old_style) + { + PR_Lock (targ->donelock); + targ->done = PR_TRUE; + PR_Unlock (targ->donelock); + } + } + +#ifdef __cplusplus +} +#endif + +int +RA_Client::OpConnUpdate (NameValueSet * params) +{ + int num_threads = params->GetValueAsInt ((char *) "num_threads", 1); + int i; + int status = 0; + PRThread **threads; + ThreadArg *arg; + + threads = (PRThread **) malloc (sizeof (PRThread *) * num_threads); + if (threads == NULL) + { + return 0; + } + arg = (ThreadArg *) malloc (sizeof (ThreadArg) * num_threads); + if (arg == NULL) + { + return 0; + } + + /* start threads */ + for (i = 0; i < num_threads; i++) + { + arg[i].time = 0; + arg[i].status = 0; + arg[i].client = this; + if (i == 0) + { + arg[i].token = &this->m_token; + } + else + { + arg[i].token = this->m_token.Clone (); + } + arg[i].params = params; + threads[i] = PR_CreateThread (PR_USER_THREAD, ThreadConnUpdate, &arg[i], PR_PRIORITY_NORMAL, /* Priority */ + PR_GLOBAL_THREAD, /* Scope */ + PR_JOINABLE_THREAD, /* State */ + 0 /* Stack Size */ + ); + } + + /* join threads */ + for (i = 0; i < num_threads; i++) + { + PR_JoinThread (threads[i]); + } + + for (i = 0; i < num_threads; i++) + { + Output ("Thread (%d) status='%d' time='%d msec'", i, + arg[i].status, arg[i].time); + } + + status = arg[0].status; + + return status; +} + +int +RA_Client::OpConnResetPin (NameValueSet * params) +{ + int num_threads = params->GetValueAsInt ((char *) "num_threads", 1); + int i; + int status = 0; + PRThread **threads; + ThreadArg *arg; + + threads = (PRThread **) malloc (sizeof (PRThread *) * num_threads); + if (threads == NULL) + { + return 0; + } + arg = (ThreadArg *) malloc (sizeof (ThreadArg) * num_threads); + if (arg == NULL) + { + return 0; + } + + /* start threads */ + for (i = 0; i < num_threads; i++) + { + arg[i].time = 0; + arg[i].status = 0; + arg[i].client = this; + if (i == 0) + { + arg[i].token = &this->m_token; + } + else + { + arg[i].token = this->m_token.Clone (); + } + arg[i].params = params; + threads[i] = PR_CreateThread (PR_USER_THREAD, ThreadConnResetPin, &arg[i], PR_PRIORITY_NORMAL, /* Priority */ + PR_GLOBAL_THREAD, /* Scope */ + PR_JOINABLE_THREAD, /* State */ + 0 /* Stack Size */ + ); + } + + /* join threads */ + for (i = 0; i < num_threads; i++) + { + PR_JoinThread (threads[i]); + } + + for (i = 0; i < num_threads; i++) + { + Output ("Thread (%d) status='%d' time='%d msec'", i, + arg[i].status, arg[i].time); + } + + status = arg[0].status; + + return status; +} + +#ifdef __cplusplus +extern "C" +{ +#endif + + static void ThreadConnEnroll (void *arg) + { + PRTime start, end; + ThreadArg *targ = (ThreadArg *) arg; + + start = PR_Now (); + RA_Conn conn (targ->client->m_vars.GetValue ("ra_host"), + atoi (targ->client->m_vars.GetValue ("ra_port")), + targ->client->m_vars.GetValue ("ra_uri")); + + if (!conn.Connect ()) + { + OutputError ("Cannot connect to %s:%d", + targ->client->m_vars.GetValue ("ra_host"), + atoi (targ->client->m_vars.GetValue ("ra_port"))); + targ->status = 0; + + if (!old_style) + { + PR_Lock (targ->donelock); + targ->done = PR_TRUE; + PR_Unlock (targ->donelock); + } + + return; + } + + NameValueSet *exts = NULL; + char *extensions = + targ->params->GetValueAsString ((char *) "extensions", NULL); + if (extensions != NULL) + { + exts = NameValueSet::Parse (extensions, "&"); + } + + RA_Begin_Op_Msg beginOp = RA_Begin_Op_Msg (OP_ENROLL, exts); + conn.SendMsg (&beginOp); + + /* handle secure ID (optional) */ + while (1) + { + RA_Msg *msg = (RA_Msg *) conn.ReadMsg (targ->token); + if (msg == NULL) + break; + if (msg->GetType () == MSG_LOGIN_REQUEST) + { + targ->status = HandleLoginRequest (targ->client, + (RA_Login_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_EXTENDED_LOGIN_REQUEST) + { + targ->status = HandleExtendedLoginRequest (targ->client, + (RA_Extended_Login_Request_Msg + *) msg, targ->token, + &conn, + &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_STATUS_UPDATE_REQUEST) + { + targ->status = + HandleStatusUpdateRequest (targ->client, + (RA_Status_Update_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, targ->params); + } + else if (msg->GetType () == MSG_SECUREID_REQUEST) + { + targ->status = HandleSecureIdRequest (targ->client, + (RA_SecureId_Request_Msg *) + msg, targ->token, &conn, + &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_ASQ_REQUEST) + { + targ->status = HandleASQRequest (targ->client, + (RA_ASQ_Request_Msg *) msg, + targ->token, &conn, + &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_TOKEN_PDU_REQUEST) + { + targ->status = HandleTokenPDURequest (targ->client, + (RA_Token_PDU_Request_Msg *) + msg, targ->token, &conn, + &targ->client->m_vars, + targ->params); + targ->status = 1; + } + else if (msg->GetType () == MSG_NEW_PIN_REQUEST) + { + targ->status = HandleNewPinRequest (targ->client, + (RA_New_Pin_Request_Msg *) + msg, targ->token, &conn, + &targ->client->m_vars, + targ->params); + } + else if (msg->GetType () == MSG_END_OP) + { + RA_End_Op_Msg *endOp = (RA_End_Op_Msg *) msg; + if (endOp->GetResult () == 0) + { + targ->status = 1; /* error */ + } + else + { + targ->status = 0; + } + if (msg != NULL) + { + delete msg; + msg = NULL; + } + break; + } + else + { + /* error */ + targ->status = 0; /* error */ + } + if (msg != NULL) + { + delete msg; + msg = NULL; + } + } + + conn.Close (); + end = PR_Now (); + targ->time = (end - start) / 1000; + + if (!old_style) + { + PR_Lock (targ->donelock); + targ->done = PR_TRUE; + PR_Unlock (targ->donelock); + } + } + +#ifdef __cplusplus +} +#endif + +int +RA_Client::OpConnEnroll (NameValueSet * params) +{ + int num_threads = params->GetValueAsInt ((char *) "num_threads", 1); + int i; + int status = 0; + PRThread **threads; + ThreadArg *arg; + + threads = (PRThread **) malloc (sizeof (PRThread *) * num_threads); + if (threads == NULL) + { + return 0; /* error */ + } + arg = (ThreadArg *) malloc (sizeof (ThreadArg) * num_threads); + if (arg == NULL) + { + return 0; + } + + /* start threads */ + for (i = 0; i < num_threads; i++) + { + arg[i].time = 0; + arg[i].status = 0; + arg[i].client = this; + if (i == 0) + { + arg[i].token = &this->m_token; + } + else + { + arg[i].token = this->m_token.Clone (); + } + arg[i].params = params; + threads[i] = PR_CreateThread (PR_USER_THREAD, ThreadConnEnroll, &arg[i], PR_PRIORITY_NORMAL, /* Priority */ + PR_GLOBAL_THREAD, /* Scope */ + PR_JOINABLE_THREAD, /* State */ + 0 /* Stack Size */ + ); + } + + /* join threads */ + for (i = 0; i < num_threads; i++) + { + PR_JoinThread (threads[i]); + } + + status = 1; + + for (i = 0; i < num_threads; i++) + { + Output ("Thread (%d) status='%d' time='%d msec'", i, + arg[i].status, arg[i].time); + if (arg[i].status != 1) + { + // if any thread fails, this operation + // is considered as failure + status = arg[i].status; + } + } + + + return status; +} + + +/* + * no more than num_threads will be running concurrently + * no more than a total of max_ops requests will be started + */ +int +StartThreads (int num_threads, ThreadArg * arg, PRThread ** threads, + int max_ops, RA_Client * _this, NameValueSet * params, + RequestType op_type) +{ + int i; + int started = 0; + + if (arg == NULL) + { + goto loser; + } + + /* start threads */ + for (i = 0; i < num_threads; i++) + { + if (started == max_ops) + { + break; + } + if (threads[i] == NULL) + { + arg[i].time = 0; + arg[i].status = 0; + arg[i].client = _this; + arg[i].done = PR_FALSE; + + if (i == 0) + { + arg[i].token = &_this->m_token; + } + else + { + + if (arg[i].token != NULL) + { + if (arg[i].token->m_pin) + { + PL_strfree (arg[i].token->m_pin); + arg[i].token->m_pin = NULL; + } + if (arg[i].token->m_session_key != NULL) + { + PORT_Free (arg[i].token->m_session_key); + arg[i].token->m_session_key = NULL; + } + if (arg[i].token->m_enc_session_key != NULL) + { + PORT_Free (arg[i].token->m_enc_session_key); + arg[i].token->m_enc_session_key = NULL; + } + if (arg[i].token->m_object != NULL) + { + delete (arg[i].token->m_object); + arg[i].token->m_object = NULL; + } + + delete (arg[i].token); + arg[i].token = NULL; + + } + + arg[i].token = _this->m_token.Clone (); + } + arg[i].params = params; + Output ("WWWWWWWWW StartThreads -- thread (%d) begins", i); + if (op_type == OP_CLIENT_ENROLL) + { + threads[i] = PR_CreateThread (PR_USER_THREAD, ThreadConnEnroll, &arg[i], PR_PRIORITY_NORMAL, /* Priority */ + PR_GLOBAL_THREAD, /* Scope */ + PR_JOINABLE_THREAD, /* State */ + 0 /* Stack Size */ + ); + } + else if (op_type == OP_CLIENT_FORMAT) + { + threads[i] = PR_CreateThread (PR_USER_THREAD, ThreadConnUpdate, &arg[i], PR_PRIORITY_NORMAL, /* Priority */ + PR_GLOBAL_THREAD, /* Scope */ + PR_JOINABLE_THREAD, /* State */ + 0 /* Stack Size */ + ); + } + else + { // OP_CLIENT_RESET_PIN + threads[i] = PR_CreateThread (PR_USER_THREAD, ThreadConnResetPin, &arg[i], PR_PRIORITY_NORMAL, /* Priority */ + PR_GLOBAL_THREAD, /* Scope */ + PR_JOINABLE_THREAD, /* State */ + 0 /* Stack Size */ + ); + } + + started++; + } + else + { + Output ("thread[%d] is not NULL", i); + } + } + +loser: + Output ("StartThreads -- %d threads started", started); + return started; +} + +/* + * no more than num_threads will be running concurrently + * no more than a total of max_ops requests will be started + */ +int +RA_Client::OpConnStart (NameValueSet * params, RequestType op_type) +{ + // number of concurrent threads + int num_threads = params->GetValueAsInt ((char *) "num_threads", 1); + // number of total enrollments + int max_ops = params->GetValueAsInt ((char *) "max_ops", num_threads); + int count = 0; + int i; + int status = 1; + int started = 0; + PRThread **threads; + ThreadArg *arg; + + threads = (PRThread **) malloc (sizeof (PRThread *) * num_threads); + if (threads == NULL) + { + return 0; /* error */ + } + arg = (ThreadArg *) malloc (sizeof (ThreadArg) * num_threads); + if (arg == NULL) + { + return 0; + } + + for (i = 0; i < num_threads; i++) + { + arg[i].donelock = PR_NewLock (); + arg[i].token = NULL; + threads[i] = NULL; + } + + count = 0; + PRBool hasFreeThread = PR_TRUE; + while (count < max_ops) + { + // fully populate the thread pool + + if (hasFreeThread) + { + started = + StartThreads (num_threads, arg, threads, max_ops - count, this, + params, op_type); + count += started; + Output ("OpConnStart: # requests started =%d", count); + hasFreeThread = PR_FALSE; + } + + // PR_Sleep(PR_MillisecondsToInterval(500)); + PR_Sleep (PR_SecondsToInterval (1)); + Output ("OpConnStart: checking for free threads..."); + // check if any threads are done + for (i = 0; i < num_threads; i++) + { + if (threads[i] != NULL) + { + PR_Lock (arg[i].donelock); + int arg_done = arg[i].done; + PR_Unlock (arg[i].donelock); + if (arg_done) + { + PR_JoinThread (threads[i]); + Output ("Thread (%d) status='%d' time='%d msec'", i, + arg[i].status, arg[i].time); + + if (arg[i].status != 1) + { + // if any thread fails, this operation + // is considered as failure + status = arg[i].status; + } + threads[i] = NULL; + + hasFreeThread = PR_TRUE; + + } + } + } + Output ("OpConnStart: done checking for free threads..."); + } // while + + Output ("OpConnStart: TOTAL REQUESTS: %d", count); + + for (i = 0; i < num_threads; i++) + { + if (threads[i] != NULL) + { + PR_JoinThread (threads[i]); + } + if (arg[i].donelock != NULL) + { + PR_DestroyLock (arg[i].donelock); + } + } + + return status; + +} + +int +RA_Client::OpVarSet (NameValueSet * params) +{ + m_vars.Add (params->GetValue ("name"), params->GetValue ("value")); + Output ("%s: '%s'", params->GetValue ("name"), + m_vars.GetValue (params->GetValue ("name"))); + return 1; +} + +int +RA_Client::OpVarDebug (NameValueSet * params) +{ + if (m_fd_debug != NULL) + { + PR_Close (m_fd_debug); + m_fd_debug = NULL; + } + m_fd_debug = PR_Open (params->GetValue ("filename"), + PR_RDWR | PR_CREATE_FILE | PR_APPEND, 400 | 200); + return 1; +} + +int +RA_Client::OpVarGet (NameValueSet * params) +{ + char *value = m_vars.GetValue (params->GetValue ("name")); + Output ("%s: '%s'", params->GetValue ("name"), value); + + return 1; +} + +int +RA_Client::OpVarList (NameValueSet * params) +{ + int i; + char *name; + + for (i = 0; i < m_vars.Size (); i++) + { + name = m_vars.GetNameAt (i); + Output ("%s: '%s'", name, m_vars.GetValue (name)); + } + return 1; +} + +/** + * Invoke operation. + */ +void +RA_Client::InvokeOperation (char *op, NameValueSet * params) +{ + PRTime start, end; + int status = 0; + + start = PR_Now (); + Debug ("RA_Client::InvokeOperation", "op='%s'", op); + int max_ops = params->GetValueAsInt ((char *) "max_ops"); + if (max_ops != 0) + old_style = PR_FALSE; + + if (strcmp (op, "help") == 0) + { + status = OpHelp (params); + } + else if (strcmp (op, "ra_format") == 0) + { + if (old_style) + status = OpConnUpdate (params); + else + status = OpConnStart (params, OP_CLIENT_FORMAT); + } + else if (strcmp (op, "ra_reset_pin") == 0) + { + if (old_style) + status = OpConnResetPin (params); + else + status = OpConnStart (params, OP_CLIENT_RESET_PIN); + } + else if (strcmp (op, "ra_enroll") == 0) + { + if (old_style) + status = OpConnEnroll (params); + else + status = OpConnStart (params, OP_CLIENT_ENROLL); + } + else if (strcmp (op, "token_status") == 0) + { + status = OpTokenStatus (params); + } + else if (strcmp (op, "token_set") == 0) + { + status = OpTokenSet (params); + } + else if (strcmp (op, "debug") == 0) + { + status = OpVarDebug (params); + } + else if (strcmp (op, "var_set") == 0) + { + status = OpVarSet (params); + } + else if (strcmp (op, "var_get") == 0) + { + status = OpVarGet (params); + } + else if (strcmp (op, "var_list") == 0) + { + status = OpVarList (params); + } + end = PR_Now (); + + if (status) + { + OutputSuccess ("Operation '%s' Success (%d msec)", op, + (end - start) / 1000); + } + else + { + OutputError ("Operation '%s' Failure (%d msec)", op, + (end - start) / 1000); + } +} + +/** + * Execute RA client. + */ +void +RA_Client::Execute () +{ + char line[1024]; + int rc; + char *op; + int done = 0; + char *lasts = NULL; + + /* start main loop */ + PrintHeader (); + while (!done) + { + PrintPrompt (); + rc = ReadLine (line, 1024); + printf ("%s\n", line); + if (rc <= 0) + { + break; /* exit if no more line */ + } + if (line[0] == '#') + { + continue; /* ignore comment line */ + } + /* format: 'op=cmd <parameters>' */ + NameValueSet *params = NameValueSet::Parse (line, " "); + if (params == NULL) + { + continue; + } + op = params->GetValue ("op"); + if (op == NULL) + { + /* user did not type op= */ + op = PL_strtok_r (line, " ", &lasts); + if (op == NULL) + continue; + } + if (strcmp (op, "exit") == 0) + { + done = 1; + } + else + { + InvokeOperation (op, params); + } + if (params != NULL) + { + delete params; + params = NULL; + } + } +} /* Execute */ + +char * +ownPasswd (PK11SlotInfo * slot, PRBool retry, void *arg) +{ + return PL_strdup ("password"); +} + +/** + * User certutil -d . -N to create a database. + * The database should have 'password' as the password. + */ +int +main (int argc, char *argv[]) +{ + char buffer[513]; + SECStatus rv; + PK11SlotInfo *slot = NULL; + PRUint32 flags = 0; + // char *newpw = NULL; + + /* Initialize NSPR & NSS */ + PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + PK11_SetPasswordFunc (ownPasswd); + rv = NSS_Initialize (".", "", "", "", flags); + if (rv != SECSuccess) + { + PR_GetErrorText (buffer); + fprintf (stderr, "unable to initialize NSS library (%d - '%s')\n", + PR_GetError (), buffer); + exit (0); + } + slot = PK11_GetInternalKeySlot (); + if (PK11_NeedUserInit (slot)) + { + rv = PK11_InitPin (slot, (char *) NULL, (char *) "password"); + if (rv != SECSuccess) + { + PR_GetErrorText (buffer); + fprintf (stderr, "unable to set new PIN (%d - '%s')\n", + PR_GetError (), buffer); + exit (0); + } + + } + if (PK11_NeedLogin (slot)) + { + rv = PK11_Authenticate (slot, PR_TRUE, NULL); + if (rv != SECSuccess) + { + PR_GetErrorText (buffer); + fprintf (stderr, "unable to authenticate (%d - '%s')\n", + PR_GetError (), buffer); + exit (0); + } + } + + /* Start RA Client */ + RA_Client client; + client.Execute (); + + /* Shutdown NSS and NSPR */ + NSS_Shutdown (); + PR_Cleanup (); + + return 1; +} diff --git a/base/tps/tools/raclient/RA_Client.h b/base/tps/tools/raclient/RA_Client.h new file mode 100644 index 000000000..6ab2ecf97 --- /dev/null +++ b/base/tps/tools/raclient/RA_Client.h @@ -0,0 +1,78 @@ +/* --- 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 --- + */ + +#ifndef RA_CLIENT_H +#define RA_CLIENT_H + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include <config.h> +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include "prthread.h" +#include "main/NameValueSet.h" +#include "RA_Conn.h" +#include "RA_Token.h" + +enum RequestType { + OP_CLIENT_ENROLL = 0, + OP_CLIENT_FORMAT = 1, + OP_CLIENT_RESET_PIN = 2 +}; + +class RA_Client +{ + public: + RA_Client(); + ~RA_Client(); + public: + int OpHelp(NameValueSet *set); + int OpConnStart(NameValueSet *set, RequestType); + int OpConnResetPin(NameValueSet *set); + int OpConnEnroll(NameValueSet *set); + int OpConnUpdate(NameValueSet *set); + int OpTokenStatus(NameValueSet *set); + int OpTokenSet(NameValueSet *set); + int OpVarList(NameValueSet *set); + int OpVarSet(NameValueSet *set); + int OpVarDebug(NameValueSet *set); + int OpVarGet(NameValueSet *set); + int OpExit(NameValueSet *set); + public: + void Debug(const char *func_name, const char *fmt, ...); + void Execute(); + void InvokeOperation(char *op, NameValueSet *set); + public: + RA_Token m_token; + NameValueSet m_vars; +}; + +#endif /* RA_CLIENT_H */ diff --git a/base/tps/tools/raclient/RA_Conn.cpp b/base/tps/tools/raclient/RA_Conn.cpp new file mode 100644 index 000000000..17a3ed34f --- /dev/null +++ b/base/tps/tools/raclient/RA_Conn.cpp @@ -0,0 +1,1037 @@ +// --- 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 "prnetdb.h" +#include "prerror.h" +#include "prio.h" +#include "plstr.h" +#include "main/NameValueSet.h" +#include "main/Util.h" +#include "RA_Conn.h" +#include "apdu/APDU_Response.h" +#include "apdu/List_Objects_APDU.h" +#include "apdu/Create_Object_APDU.h" +#include "apdu/Generate_Key_APDU.h" +#include "apdu/External_Authenticate_APDU.h" +#include "apdu/Initialize_Update_APDU.h" +#include "apdu/Lifecycle_APDU.h" +#include "apdu/Set_Pin_APDU.h" +#include "apdu/Get_Status_APDU.h" +#include "apdu/Get_Data_APDU.h" +#include "apdu/Format_Muscle_Applet_APDU.h" +#include "apdu/Load_File_APDU.h" +#include "apdu/Get_IssuerInfo_APDU.h" +#include "apdu/Set_IssuerInfo_APDU.h" +#include "apdu/Install_Applet_APDU.h" +#include "apdu/Install_Load_APDU.h" +#include "apdu/Import_Key_APDU.h" +#include "apdu/Import_Key_Enc_APDU.h" +#include "apdu/Install_Load_APDU.h" +#include "apdu/Create_Pin_APDU.h" +#include "apdu/Read_Buffer_APDU.h" +#include "apdu/List_Pins_APDU.h" +#include "apdu/Write_Object_APDU.h" +#include "apdu/Delete_File_APDU.h" +#include "apdu/Unblock_Pin_APDU.h" +#include "apdu/Select_APDU.h" +#include "apdu/Get_Version_APDU.h" +#include "apdu/Put_Key_APDU.h" +#include "msg/RA_Begin_Op_Msg.h" +#include "msg/RA_End_Op_Msg.h" +#include "msg/RA_Extended_Login_Request_Msg.h" +#include "msg/RA_Login_Request_Msg.h" +#include "msg/RA_SecureId_Request_Msg.h" +#include "msg/RA_ASQ_Request_Msg.h" +#include "msg/RA_New_Pin_Request_Msg.h" +#include "msg/RA_Status_Update_Request_Msg.h" +#include "msg/RA_Status_Update_Response_Msg.h" +#include "msg/RA_Token_PDU_Request_Msg.h" +#include "msg/RA_Login_Response_Msg.h" +#include "msg/RA_Extended_Login_Response_Msg.h" +#include "msg/RA_SecureId_Response_Msg.h" +#include "msg/RA_ASQ_Response_Msg.h" +#include "msg/RA_New_Pin_Response_Msg.h" +#include "msg/RA_Token_PDU_Response_Msg.h" +#include "engine/RA.h" + +/** + * http parameters used in the protocol + */ +#define PARAM_MSG_TYPE "msg_type" +#define PARAM_OPERATION "operation" +#define PARAM_EXTENSIONS "extensions" +#define PARAM_INVALID_PW "invalid_pw" +#define PARAM_BLOCKED "blocked" +#define PARAM_SCREEN_NAME "screen_name" +#define PARAM_PASSWORD "password" +#define PARAM_PIN_REQUIRED "pin_required" +#define PARAM_NEXT_VALUE "next_value" +#define PARAM_VALUE "value" +#define PARAM_PIN "pin" +#define PARAM_QUESTION "question" +#define PARAM_ANSWER "answer" +#define PARAM_MINIMUM_LENGTH "minimum_length" +#define PARAM_MAXIMUM_LENGTH "maximum_length" +#define PARAM_NEW_PIN "new_pin" +#define PARAM_PDU_SIZE "pdu_size" +#define PARAM_PDU_DATA "pdu_data" +#define PARAM_RESULT "result" +#define PARAM_MESSAGE "message" +#define PARAM_CURRENT_STATE "current_state" +#define PARAM_NEXT_TASK_NAME "next_task_name" + +#define MAX_RA_MSG_SIZE 4096 + +/** + * Constructs a RA connection. + */ +RA_Conn::RA_Conn (char *host, int port, char *uri) +{ + if (host == NULL) + m_host = NULL; + else + m_host = PL_strdup (host); + if (uri == NULL) + m_uri = NULL; + else + m_uri = PL_strdup (uri); + m_port = port; + m_read_header = 0; + m_fd = NULL; +} + +/** + * Destructs a RA connection. + */ +RA_Conn::~RA_Conn () +{ + if (m_host != NULL) + { + PL_strfree (m_host); + m_host = NULL; + } + if (m_uri != NULL) + { + PL_strfree (m_uri); + m_uri = NULL; + } + if (m_fd != NULL) + { + PR_Close (m_fd); + m_fd = NULL; + } +} + +static void +Output (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + printf ("Output> "); + vprintf (fmt, ap); + printf ("\n"); + va_end (ap); +} + + +#ifdef VERBOSE +static void +printBuf (Buffer * buf) +{ + int sum = 0; + + BYTE *data = *buf; + int i = 0; + if (buf->size () > 255) + { + Output ("printBuf: TOO BIG to print"); + return; + } + Output ("Begin printing buffer ====="); + for (i = 0; i < (int) buf->size (); i++) + { + printf ("%02x ", (unsigned char) data[i]); + sum++; + if (sum == 10) + { + printf ("\n"); + sum = 0; + } + } + Output ("End printing buffer ====="); +} +#endif + + +static PRUint32 +GetIPAddress (const char *hostName) +{ + const unsigned char *p; + char buf[PR_NETDB_BUF_SIZE]; + PRStatus prStatus; + PRUint32 rv = 0; + PRHostEnt prHostEnt; + + prStatus = PR_GetHostByName (hostName, buf, sizeof buf, &prHostEnt); + if (prStatus != PR_SUCCESS) + return rv; + +#undef h_addr +#define h_addr h_addr_list[0] /* address, for backward compatibility */ + + p = (const unsigned char *) (prHostEnt.h_addr); /* in Network Byte order */ + rv = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + return rv; +} + +/** + * Connects to the RA. + */ +int +RA_Conn::Connect () +{ + PRStatus rc; + char header[4096]; + + sprintf (header, "POST %s HTTP/1.1\r\n" + "Host: %s:%d\r\n" + "Transfer-Encoding: chunked\r\n" "\r\n", m_uri, m_host, m_port); + + m_fd = PR_NewTCPSocket (); + + /* + * Rifle through the values for the host + */ + + PRAddrInfo *ai; + void *iter; + PRNetAddr addr; + int family = PR_AF_INET; + + ai = PR_GetAddrInfoByName(m_host, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + if (ai) { + iter = NULL; + while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) { + family = PR_NetAddrFamily(&addr); + break; + } + PR_FreeAddrInfo(ai); + } + + PR_SetNetAddr( PR_IpAddrNull, family, m_port, &addr ); + + m_fd = PR_OpenTCPSocket( family ); + if( !m_fd ) { + return 0; + } + + rc = PR_Connect (m_fd, &addr, PR_INTERVAL_NO_TIMEOUT /* timeout */ ); + if (rc != PR_SUCCESS) + return 0; + + /* Send header */ + + PR_Send (m_fd, header, strlen (header), 0, 1000000); + + return 1; +} + +static void +CreateChunkEntity (char *msg, char *chunk, int chunk_len) +{ + int chunk_size; + int len; + Output ("***** msg = %s *****", msg); + len = strlen (msg); + sprintf (chunk, "s=%d&%s", len, msg); + chunk_size = strlen (chunk); + sprintf (chunk, "%x\r\ns=%d&%s\r\n", chunk_size, len, msg); +} + +/** + * Sends message to the RA. + */ +int +RA_Conn::SendMsg (RA_Msg * msg) +{ + char msgbuf[MAX_RA_MSG_SIZE]; + char chunk[MAX_RA_MSG_SIZE]; + + /* send chunk size */ + if (msg->GetType () == MSG_BEGIN_OP) + { + RA_Begin_Op_Msg *begin = (RA_Begin_Op_Msg *) msg; + sprintf (msgbuf, "%s=%d&%s=%d", PARAM_MSG_TYPE, MSG_BEGIN_OP, + PARAM_OPERATION, begin->GetOpType ()); + NameValueSet *exts = begin->GetExtensions (); + if (exts != NULL) + { + sprintf (msgbuf, "%s&%s=", msgbuf, PARAM_EXTENSIONS); + for (int i = 0; i < exts->Size (); i++) + { + if (i != 0) + { + sprintf (msgbuf, "%s%%26", msgbuf); + } + char *name = exts->GetNameAt (i); + sprintf (msgbuf, "%s%s=%s", + msgbuf, name, exts->GetValueAsString (name)); + } + } + CreateChunkEntity (msgbuf, chunk, 4096); + } + else if (msg->GetType () == MSG_LOGIN_RESPONSE) + { + RA_Login_Response_Msg *resp = (RA_Login_Response_Msg *) msg; + sprintf (msgbuf, "%s=%d&%s=%s&%s=%s", + PARAM_MSG_TYPE, MSG_LOGIN_RESPONSE, + PARAM_SCREEN_NAME, resp->GetUID (), + PARAM_PASSWORD, resp->GetPassword ()); + CreateChunkEntity (msgbuf, chunk, 4096); + } + else if (msg->GetType () == MSG_EXTENDED_LOGIN_RESPONSE) + { + RA_Extended_Login_Response_Msg *resp = + (RA_Extended_Login_Response_Msg *) msg; + AuthParams *auth = resp->GetAuthParams (); + sprintf (msgbuf, "%s=%d&%s=%s&%s=%s", + PARAM_MSG_TYPE, MSG_EXTENDED_LOGIN_RESPONSE, + PARAM_SCREEN_NAME, auth->GetUID (), + PARAM_PASSWORD, auth->GetPassword ()); + CreateChunkEntity (msgbuf, chunk, 4096); + } + else if (msg->GetType () == MSG_STATUS_UPDATE_RESPONSE) + { + RA_Status_Update_Response_Msg *resp = + (RA_Status_Update_Response_Msg *) msg; + int status = resp->GetStatus (); + sprintf (msgbuf, "%s=%d&%s=%d", + PARAM_MSG_TYPE, MSG_STATUS_UPDATE_RESPONSE, + PARAM_CURRENT_STATE, status); + CreateChunkEntity (msgbuf, chunk, 4096); + } + else if (msg->GetType () == MSG_SECUREID_RESPONSE) + { + RA_SecureId_Response_Msg *resp = (RA_SecureId_Response_Msg *) msg; + char *value = resp->GetValue (); + char *pin = resp->GetPIN (); + if (pin == NULL) + { + pin = (char *) ""; + } + sprintf (msgbuf, "%s=%d&%s=%s&%s=%s", + PARAM_MSG_TYPE, MSG_SECUREID_RESPONSE, + PARAM_VALUE, value, PARAM_PIN, pin); + CreateChunkEntity (msgbuf, chunk, 4096); + } + else if (msg->GetType () == MSG_ASQ_RESPONSE) + { + RA_ASQ_Response_Msg *resp = (RA_ASQ_Response_Msg *) msg; + sprintf (msgbuf, "%s=%d&%s=%s", + PARAM_MSG_TYPE, MSG_ASQ_RESPONSE, + PARAM_ANSWER, resp->GetAnswer ()); + CreateChunkEntity (msgbuf, chunk, 4096); + } + else if (msg->GetType () == MSG_NEW_PIN_RESPONSE) + { + RA_New_Pin_Response_Msg *resp = (RA_New_Pin_Response_Msg *) msg; + sprintf (msgbuf, "%s=%d&%s=%s", + PARAM_MSG_TYPE, MSG_NEW_PIN_RESPONSE, + PARAM_NEW_PIN, resp->GetNewPIN ()); + CreateChunkEntity (msgbuf, chunk, 4096); + } + else if (msg->GetType () == MSG_TOKEN_PDU_RESPONSE) + { + RA_Token_PDU_Response_Msg *resp = (RA_Token_PDU_Response_Msg *) msg; + APDU_Response *apdu_resp = resp->GetResponse (); + Buffer pdu = apdu_resp->GetData (); + char *pdu_encoded = Util::URLEncode (pdu); + sprintf (msgbuf, "%s=%d&%s=%s&%s=%d", + PARAM_MSG_TYPE, MSG_TOKEN_PDU_RESPONSE, + PARAM_PDU_DATA, pdu_encoded, PARAM_PDU_SIZE, pdu.size ()); + if (pdu_encoded != NULL) + { + PR_Free (pdu_encoded); + pdu_encoded = NULL; + } + CreateChunkEntity (msgbuf, chunk, 4096); + } + else + { + /* error */ + } + + /* send chunk */ + Output ("sending chunk ----- %s -----", chunk); + PR_Send (m_fd, chunk, strlen (chunk), 0, 1000000); + + return 1; +} + +static int +ReadResponseHeader (PRFileDesc * fd) +{ + char buf[1024]; + PRInt32 rc; + char *cur = buf; + int i; + + for (i = 0; i < 1024; i++) + { + buf[i] = 0; + } + while (1) + { + rc = PR_Recv (fd, cur, 1, 0, 1000000); + if (buf[0] == '\r' && + buf[1] == '\n' && buf[2] == '\r' && buf[3] == '\n') + { + break; + } + if (*cur == '\r') + { + cur++; + } + else if (*cur == '\n') + { + cur++; + } + else + { + cur = buf; + } + } + return 1; +} + +static int +GetChunkSize (PRFileDesc * fd) +{ + char buf[1024]; + char *cur = buf; + PRInt32 rc; + int i; + int ret; + + for (i = 0; i < 1024; i++) + { + buf[i] = 0; + } + while (1) + { + rc = PR_Recv (fd, cur, 1, 0, 1000000); + if (rc <= 0) + { + return 0; + } + if (*cur == '\r') + { + *cur = '\0'; + /* read \n */ + rc = PR_Recv (fd, cur, 1, 0, 1000000); + if (rc <= 0) + { + return 0; + } + *cur = '\0'; + break; + } + cur++; + } + sscanf (buf, "%x", (unsigned int *) (&ret)); + return ret; +} + +static int +GetChunk (PRFileDesc * fd, char *buf, int buflen) +{ + int rc = 0; + int sum = 0; + char *cur = buf; + + while (1) + { + rc = PR_Recv (fd, cur, buflen - sum, 0, 1000000); + if (rc <= 0) + { + return -1; + } + sum += rc; + cur += rc; + cur[sum] = '\0'; + if (sum == buflen) + return sum; + } +} + +bool +RA_Conn::isEncrypted () +{ + return m_encrypted_channel; +} + +void +RA_Conn::setEncryption (bool encrypted) +{ + Output ("RA_Conn::setEncryption: setting encrypted channel: %d", encrypted); + m_encrypted_channel = encrypted; +} + +APDU * +RA_Conn::CreateAPDU (RA_Token * tok, Buffer & in_apdu_data, Buffer & mac) +{ + APDU *apdu = NULL; + Buffer apdu_data; + + if (isEncrypted () && (((BYTE *) in_apdu_data)[0] == 0x84)) + { + tok->decryptMsg (in_apdu_data, apdu_data); + } + else + { + apdu_data = in_apdu_data; + } + + if (((BYTE *) apdu_data)[1] == 0x5a) + { + /* Create_Object_APDU */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + BYTE object_id[4]; + object_id[0] = ((BYTE *) apdu_data)[5]; + object_id[1] = ((BYTE *) apdu_data)[6]; + object_id[2] = ((BYTE *) apdu_data)[7]; + object_id[3] = ((BYTE *) apdu_data)[8]; + BYTE permissions[6]; + permissions[0] = ((BYTE *) apdu_data)[13]; + permissions[1] = ((BYTE *) apdu_data)[14]; + permissions[2] = ((BYTE *) apdu_data)[15]; + permissions[3] = ((BYTE *) apdu_data)[16]; + permissions[4] = ((BYTE *) apdu_data)[17]; + permissions[5] = ((BYTE *) apdu_data)[18]; + int len = + (((BYTE *) apdu_data)[9] << 24) + (((BYTE *) apdu_data)[10] << 16) + + (((BYTE *) apdu_data)[11] << 8) + ((BYTE *) apdu_data)[12]; + apdu = new Create_Object_APDU (object_id, permissions, len); + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0x82) + { + /* External_Authenticate_APDU */ + BYTE encryption = ((BYTE *) apdu_data)[2]; // P1 is sec level + if (encryption == (BYTE) 0x03) + { + setEncryption (true); + } + else + { + Output ("RA_Conn::CreateAPDU(): not encrypted"); + } + + // mac is last 8 bytes + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + Buffer *data = new Buffer (apdu_data.substr (5, 8)); + + if (isEncrypted () == true) + { + apdu = new External_Authenticate_APDU (*data, SECURE_MSG_MAC_ENC); + } + else + { + apdu = new External_Authenticate_APDU (*data, SECURE_MSG_ANY); + } + if (data != NULL) + { + delete data; + data = NULL; + } + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0x0A) + { + /* ImportKeyEnc APDU */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + Buffer *data = + new Buffer (apdu_data.substr (5, apdu_data.size () - 8 - 5)); + Buffer a; + apdu = new Import_Key_Enc_APDU ((BYTE) p[0], (BYTE) p[1], *data); + apdu->SetMAC (mac); + if (data != NULL) + { + delete data; + data = NULL; + } + + } + else if (((BYTE *) apdu_data)[1] == 0x0C) + { + /* Generate_Key_APDU */ + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + BYTE alg = ((BYTE *) apdu_data)[5]; + int keysize = (((BYTE *) apdu_data)[6] << 8) + ((BYTE *) apdu_data)[7]; + BYTE option = ((BYTE *) apdu_data)[8]; + BYTE type = ((BYTE *) apdu_data)[9]; + unsigned int wc_len = (unsigned int) ((BYTE *) apdu_data)[10]; + Buffer *wrapped_challenge = new Buffer ((BYTE *) & + ((BYTE *) apdu_data)[11], + wc_len); + Buffer *key_check = new Buffer ((BYTE *) & + ((BYTE *) apdu_data)[11 + wc_len + 1], + (unsigned int) ((BYTE *) apdu_data)[11 + + wc_len]); + apdu = + new Generate_Key_APDU (p[0], p[1], alg, keysize, option, type, + *wrapped_challenge, *key_check); + if (wrapped_challenge != NULL) + { + delete wrapped_challenge; + wrapped_challenge = NULL; + } + if (key_check != NULL) + { + delete key_check; + key_check = NULL; + } + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0x50) + { + /* Initialize_Update_APDU */ + + setEncryption (false); + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + Buffer *data = new Buffer (apdu_data.substr (5, 8)); + apdu = new Initialize_Update_APDU (p[0], p[1], *data); + if (data != NULL) + { + delete data; + data = NULL; + } + } + else if (((BYTE *) apdu_data)[1] == 0x56) + { /* Read Objects */ + BYTE p[4]; + int offset = 0; + int size = 0; + p[0] = ((BYTE *) apdu_data)[5]; + p[1] = ((BYTE *) apdu_data)[6]; + p[2] = ((BYTE *) apdu_data)[7]; + p[3] = ((BYTE *) apdu_data)[8]; + offset = (((BYTE *) apdu_data)[9] << 24) + + (((BYTE *) apdu_data)[10] << 16) + + (((BYTE *) apdu_data)[11] << 8) + ((BYTE *) apdu_data)[12]; + size = ((BYTE *) apdu_data)[13]; /* p2 */ + apdu = new Read_Object_APDU (p, offset, size); + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0x58) + { /* List Objects */ + apdu = new List_Objects_APDU (((BYTE *) apdu_data)[2]); + } + else if (((BYTE *) apdu_data)[1] == 0xf0) + { + /* Lifecycle_APDU */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + apdu = new Lifecycle_APDU (((BYTE *) apdu_data)[2]); + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0x08) + { + /* Read_BufferAPDU */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + int len = ((BYTE *) apdu_data)[2]; + int offset = (((BYTE *) apdu_data)[5] << 8) + ((BYTE *) apdu_data)[6]; + apdu = new Read_Buffer_APDU (len, offset); + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0x04) + { + /* Set_Pin_APDU */ + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + Buffer *data = + new Buffer (apdu_data.substr (5, apdu_data.size () - 8 - 5)); + apdu = new Set_Pin_APDU (p[0], p[1], *data); + if (data != NULL) + { + delete data; + data = NULL; + } + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0x2a) + { + Buffer dummy; + apdu = new Format_Muscle_Applet_APDU (0, + dummy, 0, + dummy, 0, + dummy, 0, dummy, 0, 0, 0, 0); + } + else if (((BYTE *) apdu_data)[1] == 0xe6) + { + BYTE p1 = ((BYTE *) apdu_data)[2]; /* p1 */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); +/* Why was it ignored? + Buffer dummy; + if (p1 == 0x02) { + apdu = new Install_Load_APDU(dummy, dummy, 0); + } else { + apdu = new Install_Applet_APDU(dummy, dummy, 0,0); + } +*/ + Buffer *data = + new Buffer (apdu_data.substr (5, apdu_data.size () - 8 - 5)); + if (p1 == 0x02) + { + apdu = new Install_Load_APDU (*data); + } + else + { + apdu = new Install_Applet_APDU (*data); + } + apdu->SetMAC (mac); + if (data != NULL) + { + delete data; + data = NULL; + } + } + else if (((BYTE *) apdu_data)[1] == 0xe8) + { + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + Buffer *data = + new Buffer (apdu_data.substr (5, apdu_data.size () - 8 - 5)); + apdu = new Load_File_APDU (p[0], p[1], *data); + if (data != NULL) + { + delete data; + data = NULL; + } + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0xe4) + { + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + // Delete File apdu has two extra bytes after header + // remove before proceed + Buffer *data = + new Buffer (apdu_data.substr (7, apdu_data.size () - 8 - 5 - 2)); + apdu = new Delete_File_APDU (*data); + if (data != NULL) + { + delete data; + data = NULL; + } + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0x02) + { + /* Unblock_Pin_APDU */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + apdu = new Unblock_Pin_APDU (); + apdu->SetMAC (mac); + } + else if (((BYTE *) apdu_data)[1] == 0xa4) + { /* Select */ + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + Buffer *data = NULL; + if (apdu_data.size () == 5) + { + data = new Buffer (); + } + else + { + data = new Buffer (apdu_data.substr (5, apdu_data.size () - 5)); + } + apdu = new Select_APDU (p[0], p[1], *data); + if (data != NULL) + { + delete data; + data = NULL; + } + } + else if (((BYTE *) apdu_data)[1] == 0x3C) + { /* Get Status */ + apdu = new Get_Status_APDU (); + } + else if (((BYTE *) apdu_data)[1] == 0x70) + { /* Get Version */ + apdu = new Get_Version_APDU (); + } + else if (((BYTE *) apdu_data)[1] == 0x48) + { + apdu = new List_Pins_APDU (0x02); + } + else if (((BYTE *) apdu_data)[1] == 0x40) + { /* Put Key */ + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + Buffer *data = + new Buffer (apdu_data.substr (5, apdu_data.size () - 8 - 5)); + apdu = new Create_Pin_APDU (p[0], p[1], *data); + apdu->SetMAC (mac); + if (data != NULL) + { + delete data; + data = NULL; + } + } + else if (((BYTE *) apdu_data)[1] == 0xca) + { /* Get Data */ + apdu = new Get_Data_APDU (); + } + else if (((BYTE *) apdu_data)[1] == 0xf6) + { /* Get_IssuerInfo */ + apdu = new Get_IssuerInfo_APDU (); + } + else if (((BYTE *) apdu_data)[1] == 0xf4) + { /* Set_IssuerInfo */ + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + Buffer *data = + new Buffer (apdu_data.substr (5, apdu_data.size () - 8 - 5)); + apdu = new Set_IssuerInfo_APDU (p[0], p[1], *data); + apdu->SetMAC (mac); + if (data != NULL) + { + delete data; + data = NULL; + } + } + else if (((BYTE *) apdu_data)[1] == 0xd8) + { /* Put Key */ + BYTE p[2]; + p[0] = ((BYTE *) apdu_data)[2]; /* p1 */ + p[1] = ((BYTE *) apdu_data)[3]; /* p2 */ + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + Buffer *data = + new Buffer (apdu_data.substr (5, apdu_data.size () - 8 - 5)); + apdu = new Put_Key_APDU (p[0], p[1], *data); + apdu->SetMAC (mac); + if (data != NULL) + { + delete data; + data = NULL; + } + } + else if (((BYTE *) apdu_data)[1] == 0x54) + { + /* Write_Object_APDU */ + BYTE object_id[4]; + object_id[0] = ((BYTE *) apdu_data)[5]; + object_id[1] = ((BYTE *) apdu_data)[6]; + object_id[2] = ((BYTE *) apdu_data)[7]; + object_id[3] = ((BYTE *) apdu_data)[8]; + mac = Buffer (apdu_data.substr (apdu_data.size () - 8, 8)); + int offset = + (((BYTE *) apdu_data)[9] << 24) + (((BYTE *) apdu_data)[10] << 16) + + (((BYTE *) apdu_data)[11] << 8) + ((BYTE *) apdu_data)[12]; + Buffer *data = + new Buffer (apdu_data.substr (14, apdu_data.size () - 8 - 11 - 3)); + apdu = new Write_Object_APDU (object_id, offset, *data); + apdu->SetMAC (mac); + if (data != NULL) + { + delete data; + data = NULL; + } + } + else + { + /* error */ + } + return apdu; +} + +/** + * Retrieves message from the RA. + */ +RA_Msg * +RA_Conn::ReadMsg (RA_Token * token) +{ + int len = 0; + char buf[4096]; + PRInt32 rc; + int i; + char *msg_type_s = NULL; + int msg_type; + RA_Msg *msg = NULL; + + if (!m_read_header) + { + ReadResponseHeader (m_fd); + m_read_header = 1; + } + + /* read chunk size */ + len = GetChunkSize (m_fd); + if (len <= 0) + { + return NULL; + } + + for (i = 0; i < 4096; i++) + { + buf[i] = 0; + } + + /* read chunk */ + rc = GetChunk (m_fd, buf, len + 2); + if (rc <= 0) + { + return NULL; + } + buf[len] = '\0'; + + /* parse name value pair */ + NameValueSet *params = NameValueSet::Parse (buf, "&"); + if (params == NULL) + return NULL; + msg_type_s = params->GetValue (PARAM_MSG_TYPE); + if (msg_type_s == NULL) + { + if (params != NULL) + { + delete params; + params = NULL; + } + return NULL; + } + msg_type = atoi (msg_type_s); + + if (msg_type == MSG_LOGIN_REQUEST) + { + msg = + new RA_Login_Request_Msg (atoi (params->GetValue (PARAM_INVALID_PW)), + atoi (params->GetValue (PARAM_BLOCKED))); + } + else if (msg_type == MSG_EXTENDED_LOGIN_REQUEST) + { + msg = new RA_Extended_Login_Request_Msg (0, 0, NULL, 0, NULL, NULL); + } + else if (msg_type == MSG_END_OP) + { + msg = new RA_End_Op_Msg ((RA_Op_Type) + atoi (params->GetValue (PARAM_OPERATION)), + atoi (params->GetValue (PARAM_RESULT)), + atoi (params->GetValue (PARAM_MESSAGE))); + } + else if (msg_type == MSG_SECUREID_REQUEST) + { + msg = + new + RA_SecureId_Request_Msg (atoi (params->GetValue (PARAM_PIN_REQUIRED)), + atoi (params->GetValue (PARAM_NEXT_VALUE))); + } + else if (msg_type == MSG_STATUS_UPDATE_REQUEST) + { + msg = + new + RA_Status_Update_Request_Msg (atoi + (params-> + GetValue (PARAM_CURRENT_STATE)), + params-> + GetValue (PARAM_NEXT_TASK_NAME)); + } + else if (msg_type == MSG_ASQ_REQUEST) + { + msg = new RA_ASQ_Request_Msg (params->GetValue (PARAM_QUESTION)); + } + else if (msg_type == MSG_NEW_PIN_REQUEST) + { + msg = + new + RA_New_Pin_Request_Msg (atoi + (params->GetValue (PARAM_MINIMUM_LENGTH)), + atoi (params-> + GetValue (PARAM_MAXIMUM_LENGTH))); + } + else if (msg_type == MSG_TOKEN_PDU_REQUEST) + { + char *pdu_encoded = params->GetValue (PARAM_PDU_DATA); + Buffer *apdu_data = Util::URLDecode (pdu_encoded); + +#ifdef VERBOSE + Output ("ReadMsg: URLDecoded apdu = "); + printBuf (apdu_data); +#endif + + Buffer mac; + APDU *apdu = CreateAPDU (token, *apdu_data, mac); + msg = new RA_Token_PDU_Request_Msg (apdu); + if (apdu_data != NULL) + { + delete apdu_data; + apdu_data = NULL; + } + } + else + { + /* error */ + if (params != NULL) + { + delete params; + params = NULL; + } + return NULL; + } + + if (params != NULL) + { + delete params; + params = NULL; + } + + return msg; +} + +/** + * Terminates this connection. + */ +int +RA_Conn::Close () +{ + if (m_fd != NULL) + { + PR_Close (m_fd); + m_fd = NULL; + } + return 1; +} diff --git a/base/tps/tools/raclient/RA_Conn.h b/base/tps/tools/raclient/RA_Conn.h new file mode 100644 index 000000000..307166eaf --- /dev/null +++ b/base/tps/tools/raclient/RA_Conn.h @@ -0,0 +1,71 @@ +/* --- 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 --- + */ + +#ifndef RA_CONN_H +#define RA_CONN_H + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include <config.h> +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include "prio.h" +#include "RA_Token.h" +#include "main/RA_Msg.h" +#include "main/Buffer.h" +#include "apdu/APDU.h" + +class RA_Conn +{ + public: + RA_Conn(char *host, int port, char *uri); + ~RA_Conn(); + public: + int SendMsg(RA_Msg *msg); + RA_Msg *ReadMsg(); + RA_Msg *ReadMsg(RA_Token *token); + int Connect(); + int Close(); + void setEncryption(bool encrypted); + bool isEncrypted(); + public: + APDU *CreateAPDU(RA_Token *tok, Buffer &data, Buffer &mac); + private: + char *m_host; + int m_port; + char *m_uri; + PRFileDesc *m_fd; + int m_read_header; + bool m_encrypted_channel; +}; + +#endif /* RA_MSG_H */ diff --git a/base/tps/tools/raclient/RA_Token.cpp b/base/tps/tools/raclient/RA_Token.cpp new file mode 100644 index 000000000..069d6c23c --- /dev/null +++ b/base/tps/tools/raclient/RA_Token.cpp @@ -0,0 +1,2008 @@ +// --- 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 "cryptohi.h" +#include "plstr.h" +#include "main/Util.h" +#include "RA_Token.h" +#include "apdu/APDU_Response.h" +#include "apdu/Initialize_Update_APDU.h" +#include "apdu/Generate_Key_APDU.h" +#include "apdu/Put_Key_APDU.h" +#include "apdu/Select_APDU.h" +#include "apdu/Get_Data_APDU.h" +#include "apdu/List_Objects_APDU.h" +#include "apdu/Get_IssuerInfo_APDU.h" +#include "apdu/Set_IssuerInfo_APDU.h" +#include "apdu/Read_Object_APDU.h" +#include "apdu/Get_Version_APDU.h" +#include "apdu/Get_Status_APDU.h" +#include "apdu/List_Pins_APDU.h" +#include "apdu/Create_Pin_APDU.h" +#include "keyhi.h" +#include "nss.h" +#include "cert.h" + +//#define VERIFY_PROOF + +static BYTE +ToVal (char c) +{ + if (c >= '0' && c <= '9') + { + return c - '0'; + } + else if (c >= 'A' && c <= 'Z') + { + return c - 'A' + 10; + } + else if (c >= 'a' && c <= 'z') + { + return c - 'a' + 10; + } + + /* The following return is needed to suppress compiler warnings on Linux. */ + return 0; +} + +static Buffer * +ToBuffer (char *input) +{ + int len = strlen (input) / 2; + BYTE *buffer = NULL; + + buffer = (BYTE *) malloc (len); + if (buffer == NULL) + { + return NULL; + } + + for (int i = 0; i < len; i++) + { + buffer[i] = (ToVal (input[i * 2]) * 16) + ToVal (input[i * 2 + 1]); + } + Buffer *j; + j = new Buffer (buffer, len); + + if (buffer != NULL) + { + free (buffer); + buffer = NULL; + } + + return j; +} + +/** + * Constructs a virtual token. + */ +RA_Token::RA_Token () +{ + m_session_key = NULL; + m_enc_session_key = NULL; + BYTE key_info[] = { + 0x01, 0x01 + }; + BYTE version[] = { + 0x00, 0x01, 0x02, 0x03 + }; + BYTE cuid[] = { + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09 + }; + BYTE msn[] = { + 0x00, 0x00, 0x00, 0x00 + }; + BYTE key[] = { + 0x40, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f + }; + + m_major_version = 0; + m_minor_version = 0; + + /* default setting */ + m_lifecycle_state = 0; + m_icv = Buffer (8, (BYTE) 0); + m_auth_key = Buffer (key, sizeof key); + m_mac_key = Buffer (key, sizeof key); + m_kek_key = Buffer (key, sizeof key); + m_cuid = Buffer (cuid, sizeof cuid); + m_msn = Buffer (msn, sizeof msn); + m_version = Buffer (version, sizeof version); + m_key_info = Buffer (key_info, sizeof key_info); + m_pin = PL_strdup ("password"); + m_object_len = 0; + m_object = NULL; +} + + +/** + * Destructs token. + */ +RA_Token::~RA_Token () +{ + if (m_pin != NULL) + { + PL_strfree (m_pin); + m_pin = NULL; + } + if (m_session_key != NULL) + { + PORT_Free (m_session_key); + m_session_key = NULL; + } + if (m_enc_session_key != NULL) + { + PORT_Free (m_enc_session_key); + m_enc_session_key = NULL; + } + if (m_object != NULL) + { + delete (m_object); + m_object = NULL; + } +} + +RA_Token * +RA_Token::Clone () +{ + RA_Token *token = new RA_Token (); + token->m_icv = m_icv; + /* + token->m_session_key = m_session_key; + token->m_enc_session_key = m_enc_session_key; + */ + token->m_session_key = NULL; + token->m_enc_session_key = NULL; + token->m_lifecycle_state = m_lifecycle_state; + token->m_auth_key = m_auth_key; + token->m_major_version = m_major_version; + token->m_minor_version = m_minor_version; + token->m_mac_key = m_mac_key; + token->m_kek_key = m_kek_key; + token->m_cuid = m_cuid; + token->m_version = m_version; + token->m_key_info = m_key_info; + PL_strfree (token->m_pin); + token->m_pin = PL_strdup (m_pin); + token->m_object_len = m_object_len; + return token; +} + +static void +Output (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + printf ("Output> "); + vprintf (fmt, ap); + printf ("\n"); + va_end (ap); +} + +void +printBuf (Buffer * buf) +{ + int sum = 0; + + BYTE *data = *buf; + int i = 0; + if (buf->size () > 255) + { + Output ("printBuf: TOO BIG to print"); + return; + } + Output ("Begin printing buffer ====="); + for (i = 0; i < (int) buf->size (); i++) + { + printf ("%02x ", (unsigned char) data[i]); + sum++; + if (sum == 10) + { + printf ("\n"); + sum = 0; + } + } + Output ("End printing buffer ====="); +} + +Buffer & RA_Token::GetCUID () +{ + return m_cuid; +} + +Buffer & RA_Token::GetMSN () +{ + return m_msn; +} + +void +RA_Token::SetCUID (Buffer & cuid) +{ + m_cuid = cuid; +} + +void +RA_Token::SetMSN (Buffer & msn) +{ + m_msn = msn; +} + +Buffer & RA_Token::GetAppletVersion () +{ + return m_version; +} + +void +RA_Token::SetAppletVersion (Buffer & version) +{ + m_version = version; +} + +void +RA_Token::SetMajorVersion (int v) +{ + m_major_version = v; +} + +void +RA_Token::SetMinorVersion (int v) +{ + m_minor_version = v; +} + +void +RA_Token::SetAuthKey (Buffer & key) +{ + m_auth_key = key; +} + +void +RA_Token::SetMacKey (Buffer & key) +{ + m_mac_key = key; +} + +void +RA_Token::SetKekKey (Buffer & key) +{ + m_kek_key = key; +} + +Buffer & RA_Token::GetKeyInfo () +{ + return m_key_info; +} + +void +RA_Token::SetKeyInfo (Buffer & key_info) +{ + m_key_info = key_info; +} + +int +RA_Token::GetMajorVersion () +{ + return m_major_version; +} + +int +RA_Token::GetMinorVersion () +{ + return m_minor_version; +} + +BYTE +RA_Token::GetLifeCycleState () +{ + return m_lifecycle_state; +} + +char * +RA_Token::GetPIN () +{ + return m_pin; +} + +Buffer & RA_Token::GetAuthKey () +{ + return m_auth_key; +} + +Buffer & RA_Token::GetMacKey () +{ + return m_mac_key; +} + +Buffer & RA_Token::GetKekKey () +{ + return m_kek_key; +} + +int +RA_Token::NoOfPrivateKeys () +{ + SECKEYPrivateKeyList *list = NULL; + SECKEYPrivateKeyListNode *node; + PK11SlotInfo *slot = PK11_GetInternalKeySlot (); + int count; + + list = PK11_ListPrivateKeysInSlot (slot); + for (count = 0, node = PRIVKEY_LIST_HEAD (list); + !PRIVKEY_LIST_END (node, list); + node = PRIVKEY_LIST_NEXT (node), count++) + { + /* nothing */ + } + if (list != NULL) + { + SECKEY_DestroyPrivateKeyList (list); + list = NULL; + } + + return count; +} + +SECKEYPrivateKey * +RA_Token::GetPrivateKey (int pos) +{ + SECKEYPrivateKeyList *list = NULL; + SECKEYPrivateKeyListNode *node; + PK11SlotInfo *slot = PK11_GetInternalKeySlot (); + int count; + + list = PK11_ListPrivateKeysInSlot (slot); + for (count = 0, node = PRIVKEY_LIST_HEAD (list); + !PRIVKEY_LIST_END (node, list); + node = PRIVKEY_LIST_NEXT (node), count++) + { + if (pos == count) + { + return node->key; + } + } + if (list != NULL) + { + SECKEY_DestroyPrivateKeyList (list); + list = NULL; + } + + return NULL; +} + +int +RA_Token::NoOfCertificates () +{ + CERTCertList *clist = NULL; + CERTCertListNode *cln; + PK11SlotInfo *slot = PK11_GetInternalKeySlot (); + int count = 0; + + clist = PK11_ListCertsInSlot (slot); + for (cln = CERT_LIST_HEAD (clist); !CERT_LIST_END (cln, clist); + cln = CERT_LIST_NEXT (cln)) + { + count++; + } + + return count; +} + +CERTCertificate * +RA_Token::GetCertificate (int pos) +{ + CERTCertList *clist = NULL; + CERTCertListNode *cln; + PK11SlotInfo *slot = PK11_GetInternalKeySlot (); + int count = 0; + + clist = PK11_ListCertsInSlot (slot); + for (cln = CERT_LIST_HEAD (clist); !CERT_LIST_END (cln, clist); + cln = CERT_LIST_NEXT (cln)) + { + if (count == pos) + { + CERTCertificate *cert = cln->cert; + return cert; + } + count++; + } + + return NULL; +} + +void +RA_Token::decryptMsg (Buffer & in_data, Buffer & out_data) +{ + Output ("RA_Token::decryptMsg: decryption about to proceed"); + + //add this header back later...does not include lc, since it might change + Buffer header = in_data.substr (0, 4); +#ifdef VERBOSE + Output ("input data ="); + printBuf (&in_data); + Output ("length = %d", in_data.size ()); +#endif + + //add this mac back later + Buffer mac = in_data.substr (in_data.size () - 8, 8); + +#ifdef VERBOSE + Output ("mac="); + printBuf (&mac); +#endif + + // encrypted data area is the part without header and mac + Buffer enc_in_data = in_data.substr (5, in_data.size () - 8 - 5); + +#ifdef VERBOSE + Output ("RA_Token::decryptMsg: enc_in_data size: %d", enc_in_data.size ()); + Output ("encrypted in_data ="); + printBuf (&enc_in_data); +#endif + + Buffer d_apdu_data; + PRStatus status = Util::DecryptData (GetEncSessionKey (), + enc_in_data, d_apdu_data); +#ifdef VERBOSE + Output ("RA_Token::decryptMsg: decrypted data size = %d, data=", + d_apdu_data.size ()); + printBuf (&d_apdu_data); +#endif + + if (status == PR_SUCCESS) + { + Output ("RA_Token::decryptMsg: decrypt success"); + } + else + { + Output ("RA_Token::decryptMsg: decrypt failure"); + // return NULL; + } + + /* + * the original (pre-encrypted) data would look like the following + * orig. Length | Data... | <80> | <padding> + * where orig. Length is one byte, + * if orig Length + 1byte length is multiple of 8, + * it wasn't padded + * if orig Length + 1byte length is not multiple of 8, + * '80' was appended to the right of data field + * if that was multiple was 8, it's done, otherwise + * it was padded with 0 until the data len is a multiple of 8 + */ + int origLen = (int) ((BYTE *) d_apdu_data)[0]; + Output ("RA_Token::decryptMsg: origLen = %d", origLen); + + Buffer orig_data; + + // this should perfectly skip the paddings, if was any + orig_data = d_apdu_data.substr (1, origLen); + out_data = header; + out_data += Buffer (1, ((BYTE *) d_apdu_data)[0] + 0x08); + out_data += orig_data; + out_data += mac; + +#ifdef VERBOSE + Output ("decrypted pdu data:"); + printBuf (&out_data); +#endif +} + +APDU_Response * +RA_Token::ProcessInitializeUpdate (Initialize_Update_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + BYTE requested_version = apdu->GetP1 (); + //BYTE requested_index = apdu->GetP2(); + Buffer host_challenge = apdu->GetHostChallenge (); + m_host_challenge = host_challenge; +// printf("Host Challenge: \n"); +// host_challenge.dump(); + + Buffer ki = GetKeyInfo (); + BYTE current_version = ((BYTE *) ki)[0]; + //BYTE current_index = ((BYTE*)ki)[1]; + + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_iu_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_iu_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (requested_version != 0x00 && requested_version != current_version) + { + // return an error + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + m_icv = Buffer (8, (BYTE) 0); + + /** + * Initialize Update response: + * Key Diversification Data - 10 bytes + * Key Information Data - 2 bytes + * Card Challenge - 8 bytes + * Card Cryptogram - 8 bytes + */ + Buffer card_challenge (8, (BYTE) 0); + Util::GetRandomChallenge (card_challenge); + m_card_challenge = card_challenge; + + /* compute cryptogram */ + Buffer icv = Buffer (8, (BYTE) 0); + Buffer input = host_challenge + card_challenge; + Buffer cryptogram (8, (BYTE) 0); + + Buffer authkey = GetAuthKey (); + if (authkey == NULL) + { + return NULL; + } + PK11SymKey *encAuthKey = Util::DeriveKey (GetAuthKey (), + host_challenge, card_challenge); + Util::ComputeMAC (encAuthKey, input, icv, cryptogram); + + // printf("Cryptogram: \n"); + // cryptogram.dump(); + // + // establish session key + m_session_key = CreateSessionKey (mac, m_card_challenge, m_host_challenge); + // establish Encryption session key + m_enc_session_key = CreateSessionKey (auth, m_card_challenge, + m_host_challenge); + + Buffer data = GetCUID () + GetKeyInfo () + + card_challenge + cryptogram + + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + + return apdu_resp; +} + +int +RA_Token::VerifyMAC (APDU * apdu) +{ + Buffer data; + Buffer mac = apdu->GetMAC (); + + Output ("RA_Token::VerifyMAC: Begins==== apdu type =%d", apdu->GetType ()); + if (mac.size () != 8) + { + Output ("RA_Token::VerifyMAC: no mac? ok"); + return 1; + } + + Buffer new_mac = Buffer (8, (BYTE) 0); + + ComputeAPDUMac (apdu, new_mac); + if (new_mac != mac) + { +#ifdef VERBOSE + Output ("old mac: "); + printBuf (&mac); + Output ("new mac: "); + printBuf (&new_mac); +#endif + Output ("RA_Token::VerifyMAC: *** failed ***"); + return 0; + } + else + { + Output ("RA_Token::VerifyMAC: passed"); + return 1; + } +} + +void +RA_Token::ComputeAPDUMac (APDU * apdu, Buffer & new_mac) +{ + Buffer data; + + apdu->GetDataToMAC (data); + +#ifdef VERBOSE + Output ("RA_Token::ComputeAPDUMac: data to mac ="); + printBuf (&data); + Output ("RA_Token::ComputeAPDUMac: current m_icv ="); + printBuf (&m_icv); +#endif + + + Util::ComputeMAC (m_session_key, data, m_icv, new_mac); +#ifdef VERBOSE + Output ("RA_Token::ComputeAPDUMac: got new mac ="); +#endif + printBuf (&new_mac); + + + m_icv = new_mac; +} /* EncodeAPDUMac */ + +PK11SymKey * +RA_Token::GetEncSessionKey () +{ + return m_enc_session_key; +} + +PK11SymKey * +RA_Token::CreateSessionKey (keyType keytype, Buffer & card_challenge, + Buffer & host_challenge) +{ + BYTE *key = NULL; + char input[16]; + int i; + BYTE *cc = (BYTE *) card_challenge; + int cc_len = card_challenge.size (); + BYTE *hc = (BYTE *) host_challenge; + int hc_len = host_challenge.size (); + + if (keytype == mac) + key = (BYTE *) m_mac_key; + else if (keytype == auth) + key = (BYTE *) m_auth_key; + else + key = (BYTE *) m_mac_key; // for now + + /* copy card and host challenge into input buffer */ + for (i = 0; i < 8; i++) + { + input[i] = cc[i]; + } + for (i = 0; i < 8; i++) + { + input[8 + i] = hc[i]; + } + + PK11SymKey *session_key = + Util::DeriveKey (Buffer (key, 16), Buffer (hc, hc_len), + Buffer (cc, cc_len)); + + //printf("XXX mac key\n"); + //m_mac_key.dump(); + //printf("XXX card challenge\n"); + //card_challenge.dump(); + //printf("XXX host challenge\n"); + //host_challenge.dump(); + SECItem *data = PK11_GetKeyData (session_key); + Buffer db = Buffer (data->data, data->len); + // printf("session key:\n"); + // db.dump(); + + return session_key; +} + +APDU_Response * +RA_Token::ProcessExternalAuthenticate (External_Authenticate_APDU * apdu, + NameValueSet * vars, + NameValueSet * params) +{ + Buffer host_cryptogram = apdu->GetHostCryptogram (); + +#ifdef VERBOSE + Output ("RA_Token::ProcessExternalAuthenticate"); +#endif + // printf("Host Cryptogram: \n"); + // host_cryptogram.dump(); + + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_ea_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_ea_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +static int +VerifyProof (SECKEYPublicKey * pk, SECItem * siProof, + unsigned short pkeyb_len, unsigned char *pkeyb, + Buffer * challenge) +{ + // this doesn't work, and not needed anymore + return 1; + + int rs = 1; + unsigned short i = 0; + unsigned int j = 0; + unsigned char *chal = NULL; + + VFYContext *vc = VFY_CreateContext (pk, siProof, + SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE, + NULL); + if (vc == NULL) + { + Output ("VerifyProof: CreateContext failed"); + return 0; // error + } + + SECStatus vs = VFY_Begin (vc); + if (vs == SECFailure) + { + rs = -1; + Output ("VerifyProof: Begin failed"); + goto loser; + } + unsigned char proof[1024]; + + for (i = 0; i < pkeyb_len; i++) + { + proof[i] = pkeyb[i]; + } + chal = (unsigned char *) (BYTE *) (*challenge); + + for (j = 0; j < challenge->size (); i++, j++) + { + proof[i] = chal[j]; + } + vs = + VFY_Update (vc, (unsigned char *) proof, pkeyb_len + challenge->size ()); + if (vs == SECFailure) + { + rs = -1; + Output ("VerifyProof: Update failed"); + goto loser; + } + vs = VFY_End (vc); + if (vs == SECFailure) + { + rs = -1; + Output ("VerifyProof: End failed"); + goto loser; + } + else + { + Output ("VerifyProof good"); + } + +loser: + if (vc != NULL) + { + VFY_DestroyContext (vc, PR_TRUE); + vc = NULL; + } + return rs; + +} + +static Buffer +GetMusclePublicKeyData (SECKEYPublicKey * pubKey, int keylen) +{ + int i, j; + + Buffer pk = Buffer (4 /* header len */ + + pubKey->u.rsa.modulus.len + + pubKey->u.rsa.publicExponent.len); + + ((BYTE *) pk)[0] = 0; /* BLOB_ENC_PLAIN */ + ((BYTE *) pk)[1] = 0x01; /* Public RSA Key */ + ((BYTE *) pk)[2] = keylen / 256; + ((BYTE *) pk)[3] = keylen % 256; + ((BYTE *) pk)[4] = pubKey->u.rsa.modulus.len / 256; + ((BYTE *) pk)[5] = pubKey->u.rsa.modulus.len % 256; + for (i = 0; i < (int) pubKey->u.rsa.modulus.len; i++) + { + ((BYTE *) pk)[6 + i] = pubKey->u.rsa.modulus.data[i]; + } + ((BYTE *) pk)[i++] = pubKey->u.rsa.publicExponent.len / 256; + ((BYTE *) pk)[i++] = pubKey->u.rsa.publicExponent.len % 256; + for (j = 0; j < (int) pubKey->u.rsa.publicExponent.len; j++) + { + ((BYTE *) pk)[i++] = pubKey->u.rsa.publicExponent.data[j]; + } + return pk; +} + +static Buffer +Sign (SECKEYPrivateKey * privKey, Buffer & blob) +{ + SECStatus status; + + SECItem sigitem; + int signature_len; + + signature_len = PK11_SignatureLen (privKey); + sigitem.len = signature_len; + sigitem.data = (unsigned char *) PORT_Alloc (signature_len); + + status = SEC_SignData (&sigitem, (BYTE *) blob, blob.size (), privKey, + SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE); + if (status != SECSuccess) + { + printf ("Signing error\n"); + if (sigitem.data != NULL) + { + PORT_Free (sigitem.data); + sigitem.data = NULL; + } + return Buffer (16, (BYTE) 0); // sucks + } + + Buffer proof = Buffer (sigitem.data, signature_len); + if (sigitem.data != NULL) + { + PORT_Free (sigitem.data); + sigitem.data = NULL; + } + return proof; +} + +static Buffer +GetKeyBlob (int keysize, SECKEYPublicKey * pubKey) +{ + Buffer blob = Buffer (1, (BYTE) 0) + /* encoding */ + Buffer (1, (BYTE) 1) + /* key type */ + Buffer (1, (BYTE) (keysize >> 8) & 0xff) + /* key size */ + Buffer (1, (BYTE) keysize & 0xff) + /* key size */ + Buffer (1, (BYTE) (pubKey->u.rsa.modulus.len >> 8) & 0xff) + + Buffer (1, (BYTE) pubKey->u.rsa.modulus.len & 0xff) + + Buffer ((BYTE *) pubKey->u.rsa.modulus.data, pubKey->u.rsa.modulus.len) + + Buffer (1, (BYTE) (pubKey->u.rsa.publicExponent.len >> 8) & 0xff) + + Buffer (1, (BYTE) pubKey->u.rsa.publicExponent.len & 0xff) + + Buffer ((BYTE *) pubKey->u.rsa.publicExponent.data, + pubKey->u.rsa.publicExponent.len); + return blob; +} + +static Buffer +GetSignBlob (Buffer & muscle_public_key, Buffer & challenge) +{ + int i, j; + + Buffer data = Buffer (muscle_public_key.size () + + challenge.size (), (BYTE) 0); + for (i = 0; i < (int) muscle_public_key.size (); i++) + { + ((BYTE *) data)[i] = ((BYTE *) muscle_public_key)[i]; + } + for (j = 0; j < (int) challenge.size (); j++, i++) + { + ((BYTE *) data)[i] = ((BYTE *) challenge)[j]; + } + return data; +} + +APDU_Response * +RA_Token::ProcessGenerateKey (Generate_Key_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + CK_MECHANISM_TYPE mechanism; + SECOidTag algtag; + PK11RSAGenParams rsaparams; + void *x_params; + SECKEYPrivateKey *privKey; + SECKEYPublicKey *pubKey; + PK11SlotInfo *slot = PK11_GetInternalKeySlot (); + int publicExponent = 0x010001; + int buffer_size; + // RA::Debug( LL_PER_PDU, + // "RA_Token::ProcessGenerateKey: ", + // "=====ProcessGenerateKey():in ProcessGenerateKey====" ); + + // for testing only +#ifdef VERBOSE + Output ("RA_Token::ProcessGenerateKey"); +#endif + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_gk_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_gk_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer req = apdu->GetData (); + BYTE *raw = (BYTE *) req; + // BYTE alg = (BYTE)req[5]; + int keysize = (((BYTE *) req)[1] << 8) + ((BYTE *) req)[2]; +// printf("Requested key size %d\n", keysize); + + int wrapped_challenge_len = ((BYTE *) req)[5]; +// printf("Challenged Size=%d\n", wrapped_challenge_len); + Buffer wrapped_challenge = Buffer ((BYTE *) & raw[6], + wrapped_challenge_len); + + rsaparams.keySizeInBits = keysize; + rsaparams.pe = publicExponent; + mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + algtag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + x_params = &rsaparams; + + /* generate key pair */ + char *keygen_param = params->GetValue ("keygen"); + if (keygen_param == NULL || (strcmp (keygen_param, "true") == 0)) + { + privKey = PK11_GenerateKeyPair (slot, mechanism, + x_params, &pubKey, + PR_FALSE /*isPerm */ , + PR_TRUE /*isSensitive */ , + NULL /*wincx */ ); + if (privKey == NULL) + { + // printf("privKey == NULL\n"); + buffer_size = 1024; /* testing */ + } + else + { + + /* put key in the buffer */ + // printf("modulus len %d\n", pubKey->u.rsa.modulus.len); + // printf("exponent len %d\n", pubKey->u.rsa.publicExponent.len); + + Buffer blob = GetKeyBlob (keysize, pubKey); + +/* + * The key generation operation creates a proof-of-location for the + * newly generated key. This proof is a signature computed with the + * new private key using the RSA-with-MD5 signature algorithm. The + * signature is computed over the Muscle Key Blob representation of + * the new public key and the challenge sent in the key generation + * request. These two data fields are concatenated together to form + * the input to the signature, without any other data or length fields. + */ + + Buffer challenge = Buffer (16, (BYTE) 0x00); + // printf("Encrypted Enrollment Challenge:\n"); + // wrapped_challenge.dump(); + Util::DecryptData (m_kek_key, wrapped_challenge, challenge); + +// printf("Enrollment Challenge:\n"); +// challenge.dump(); +// printf("after challenge dump"); + Buffer muscle_public_key = GetMusclePublicKeyData (pubKey, keysize); +// printf("after muscle_public_key get, muscle_public_key size=%d", muscle_public_key.size()); + Buffer data_blob = GetSignBlob ( /*muscle_public_key */ blob, + challenge); +// printf("after getsignblob, blob size =%d",blob.size()); + Buffer proof = Sign (privKey, data_blob); +// printf("begin verifying proof"); + unsigned char *pkeyb = (unsigned char *) (BYTE *) data_blob; + int pkeyb_len = data_blob.size (); + + SECItem siProof; + siProof.type = (SECItemType) 0; + siProof.data = (unsigned char *) proof; + siProof.len = proof.size (); + + // int size = data_blob.size(); + // RA::Debug( LL_PER_PDU, + // "RA_Token::ProcessGenerateKey: ", + // "==== proof size =%d, data_blob size=%d", + // siProof.len, + // data_blob.size() ); + // RA::Debug( LL_PER_PDU, + // "RA_Token::ProcessGenerateKey: ", + // "==== === printing blob. size=%d", + // size ); + // RA::Debug( LL_PER_PDU, + // "RA_Token::ProcessGenerateKey: ", + // "pubKey->u.rsa.publicExponent.data[37] =%d", + // pubKey->u.rsa.publicExponent.data[37] ); + + if (VerifyProof (pubKey, &siProof, pkeyb_len, pkeyb, &challenge) != + 1) + { + + Output ("VerifyProof failed"); + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + + } + + m_buffer = + Buffer (1, (BYTE) (blob.size () / 256)) + + Buffer (1, (BYTE) (blob.size () % 256)) + + Buffer (blob) + + Buffer (1, (BYTE) (proof.size () / 256)) + + Buffer (1, (BYTE) (proof.size () % 256)) + Buffer (proof); + buffer_size = m_buffer.size (); + } // if private key not NULL + + } + else + { + // fake key + BYTE fake_key[] = { + 0x00, 0x8b, 0x00, 0x01, 0x04, 0x00, 0x00, 0x80, 0x9f, 0xf9, + 0x6e, 0xa6, 0x6c, 0xd9, 0x4b, 0x5c, 0x1a, 0xb6, 0xd8, 0x78, + 0xd2, 0xaf, 0x45, 0xd5, 0xce, 0x8a, 0xee, 0x69, 0xfc, 0xdb, + 0x16, 0x21, 0x46, 0x61, 0xb9, 0x91, 0x5d, 0xa8, 0x41, 0x3f, + 0x5c, 0xce, 0xce, 0x16, 0x0b, 0xc3, 0x16, 0x99, 0xb7, 0x81, + 0xe9, 0x9c, 0xe5, 0x31, 0x04, 0x6d, 0xab, 0xb2, 0xa3, 0xac, + 0x91, 0x2b, 0xbd, 0x9b, 0x48, 0xa8, 0xd7, 0xd8, 0x34, 0x67, + 0x4d, 0x58, 0xd3, 0xb9, 0x81, 0x4f, 0x8c, 0xf1, 0x2c, 0x92, + 0xfa, 0xe7, 0x98, 0x72, 0xea, 0x52, 0xbb, 0x43, 0x73, 0x9e, + 0x88, 0xdc, 0x6c, 0x44, 0xf3, 0x6d, 0xfd, 0x36, 0xa6, 0x5c, + 0x61, 0x7d, 0x88, 0x51, 0xc7, 0x32, 0x14, 0x64, 0xf3, 0xe0, + 0x6f, 0xfa, 0x86, 0x1d, 0xad, 0x6c, 0xdb, 0x8a, 0x1c, 0x30, + 0xb2, 0x46, 0x26, 0xba, 0x3c, 0x71, 0x2c, 0x03, 0x45, 0x97, + 0x7f, 0xb0, 0x10, 0x24, 0xf4, 0x45, 0x00, 0x03, 0x01, 0x00, + 0x01, 0x00, 0x80, 0x58, 0x06, 0x40, 0x4e, 0x05, 0xd8, 0x54, + 0x87, 0xb1, 0x5b, 0xfc, 0x67, 0x95, 0xe5 + }; + m_buffer = Buffer ((BYTE *) fake_key, sizeof fake_key); + buffer_size = m_buffer.size (); + } + + + Buffer data = Buffer (1, (BYTE) (buffer_size >> 8) & 0xff) + // key length + Buffer (1, (BYTE) buffer_size & 0xff) + // key length + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessCreateObject (Create_Object_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + Buffer inputdata; + m_chunk_len = 0; + m_object_len = 0; + +#ifdef VERBOSE + Output ("RA_Token::ProcessCreateObject"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_co_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_co_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + inputdata = apdu->GetData (); +// inputdata.dump(); + m_objectid[0] = (char) (((BYTE *) inputdata)[0]); + m_objectid[1] = (char) (((BYTE *) inputdata)[1]); + m_objectid[2] = '\0'; + +// skip permissions + + m_object_len += (((BYTE *) inputdata)[4]) << 24; + m_object_len += (((BYTE *) inputdata)[5]) << 16; + m_object_len += (((BYTE *) inputdata)[6]) << 8; + m_object_len += ((BYTE *) inputdata)[7]; + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + if (m_object != NULL) + { + delete m_object; + m_object = NULL; + } + m_object = new Buffer (m_object_len, (BYTE) 0); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessLifecycle (Lifecycle_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + +#ifdef VERBOSE + Output ("RA_Token::ProcessLifecycle"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_lc_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_lc_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessDeleteFile (Delete_File_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ +#ifdef VERBOSE + Output ("RA_Token::ProcessDeleteFile"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_df_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_df_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessInstallApplet (Install_Applet_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ +#ifdef VERBOSE + Output ("RA_Token::InstallApplet"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_ia_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_ia_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessInstallLoad (Install_Load_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ +#ifdef VERBOSE + Output ("RA_Token::InstallLoad"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_il_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_il_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessLoadFile (Load_File_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ +#ifdef VERBOSE + Output ("RA_Token::ProcessLoadFile"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_lf_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_lf_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessFormatMuscleApplet (Format_Muscle_Applet_APDU * apdu, + NameValueSet * vars, + NameValueSet * params) +{ + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessSelect (Select_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_se_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_se_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessListPins (List_Pins_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_lp_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_lp_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + Buffer data = m_version + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessGetIssuerInfo (Get_IssuerInfo_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_cp_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_cp_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = m_version + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessSetIssuerInfo (Set_IssuerInfo_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_cp_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_cp_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = m_version + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessCreatePin (Create_Pin_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_cp_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_cp_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = m_version + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessGetVersion (Get_Version_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_gv_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_gv_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = m_version + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessGetData (Get_Data_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_gd_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_gd_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + + m_cuid.substr (0, 4) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + m_cuid.substr (6, 4) + + m_cuid.substr (4, 2) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x00) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x00) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + m_msn.substr (0, 4) + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessGetStatus (Get_Status_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_gs_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_gs_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + //Return a reasonable value for available applet memory. + //Free mem - 8192 + //Tot mem - 8447 + BYTE free_mem_high = 0x20; + BYTE free_mem_low = 0x00; + BYTE tot_mem_high = 0x20; + BYTE tot_mem_low = 0xff; + Buffer data = + Buffer (1, (BYTE) m_major_version) + Buffer (1, (BYTE) m_minor_version) + + Buffer (1, (BYTE) 0x00) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) tot_mem_high) + Buffer (1, (BYTE) tot_mem_low) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) free_mem_high) + Buffer (1, (BYTE) free_mem_low) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x01) + Buffer (1, (BYTE) 0x00) + + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessPutKey (Put_Key_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ +#ifdef VERBOSE + Output ("RA_Token::ProcessPutKey"); +#endif + Buffer key_set_data = apdu->GetData (); + BYTE current_version = ((BYTE *) key_set_data)[0]; + BYTE current_index = (apdu->GetP2 () & 0x0f); + + BYTE ki[2] = { current_version, current_index }; + Buffer kib (ki, 2); + SetKeyInfo (kib); + + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_pk_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_pk_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + //BYTE new_version = key_set_data[0]; + Buffer e_auth = key_set_data.substr (3, 16); + Buffer e_mac = key_set_data.substr (25, 16); + Buffer e_kek = key_set_data.substr (47, 16); + + // need to retrieve the old kek, and decrypt the data + // with it + Buffer auth; + Buffer mac; + Buffer kek; + Util::DecryptData (m_kek_key, e_auth, auth); + Util::DecryptData (m_kek_key, e_mac, mac); + Util::DecryptData (m_kek_key, e_kek, kek); + + m_kek_key = kek; + m_mac_key = mac; + m_auth_key = auth; + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessImportKeyEnc (Import_Key_Enc_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ +#ifdef VERBOSE + Output ("RA_Token::ProcessImportKeyEnc"); +#endif + Buffer data; + + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_ik_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_ik_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + data = apdu->GetData (); + + data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessReadBuffer (Read_Buffer_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + Buffer buffer; + +#ifdef VERBOSE + Output ("RA_Token::ProcessReadBuffer"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_rb_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_rb_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + int len = apdu->GetLen (); + int offset = apdu->GetOffset (); + + if (offset + len <= (int) m_buffer.size ()) + { + buffer = m_buffer.substr (offset, len); + } + else + { + Output ("TESTING offset = %d, len = %d, m_buffer.size = %d", + offset, len, m_buffer.size ()); + buffer = Buffer (len, (BYTE) 0); /* for testing */ + } + Buffer data = buffer + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessUnblockPin (Unblock_Pin_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ +#ifdef VERBOSE + Output ("RA_Token::ProcessUnblockPin"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_up_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_up_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessListObjects (List_Objects_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_lo_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_lo_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer data = Buffer (1, (BYTE) 0x9C) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessReadObject (Read_Object_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + Buffer buffer; + +#ifdef VERBOSE + Output ("RA_Token::ProcessReadObject"); +#endif + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_ro_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_ro_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + + Buffer buf = apdu->GetData(); + int len = ((BYTE*)buf)[8]; + int offset = (((BYTE*)buf)[4] << 24) + (((BYTE*)buf)[5] << 16) + + (((BYTE*)buf)[6] << 8) + ((BYTE*)buf)[7]; + + if (offset + len <= (int) m_buffer.size ()) + { + buffer = m_buffer.substr (offset, len); + } + else + { + Output ("TESTING offset = %d, len = %d, m_buffer.size = %d", + offset, len, m_buffer.size ()); + buffer = Buffer (len, (BYTE) 0); /* for testing */ + } + + Buffer data = buffer + Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessWriteBuffer (Write_Object_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ +#ifdef VERBOSE + Output ("RA_Token::ProcessWriteBuffer"); +#endif +#define MAX_WRITE_BUFFER_SIZE 0x40 + int num = 0; + int rv = -1; + int index = MAX_WRITE_BUFFER_SIZE + 2; + PK11SlotInfo *slot; + CERTCertificate *cert = NULL; + + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_wb_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_wb_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } + Buffer inputdata = apdu->GetData (); + num = m_object_len - m_chunk_len; + if (num > MAX_WRITE_BUFFER_SIZE) + { + for (int i = 2; i < index; i++) + { + BYTE data = ((BYTE *) inputdata)[i]; + ((BYTE *) * m_object)[m_chunk_len] = data; + m_chunk_len++; + } + } + else + { + for (int i = 2; i < num + 2; i++) + { + ((BYTE *) * m_object)[m_chunk_len] = ((BYTE *) inputdata)[i]; + m_chunk_len++; + } + + if (strcmp (m_objectid, "C0") == 0) + { + // printf("RA_Token::ProcessWriteBuffer objectid = %s\n", m_objectid); + // we got the whole certificate, import to the db. + cert = CERT_DecodeCertFromPackage ((char *) ((BYTE *) * m_object), + m_object->size ()); + if (cert == NULL) + { + // printf("cert is NULL\n"); + } + else + { + slot = PK11_GetInternalKeySlot (); + + rv = PK11_Authenticate (slot, PR_TRUE, NULL); + if (rv != SECSuccess) + { + // printf("Failed to authenticate to the internal token\n"); + } + else + { + rv = PK11_ImportCert (slot, cert, CK_INVALID_HANDLE, + (char *) "testcert", PR_FALSE); + if (rv != SECSuccess) + { + printf + ("Failed to import the cert to the internal token\n"); + } + } + } + } + } + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::ProcessSetPin (Set_Pin_APDU * apdu, + NameValueSet * vars, NameValueSet * params) +{ + Buffer new_pin_buf = apdu->GetNewPIN (); +#ifdef VERBOSE + Output ("RA_Token::ProcessSetPin"); +#endif + + // for testing only + if (vars->GetValueAsBool("test_enable", 0) == 1) { + if (vars->GetValueAsBool("test_apdu_sp_return_enable", 0) == 1) { + Buffer *data = ToBuffer (vars->GetValue ("test_apdu_sp_return")); + APDU_Response *apdu_resp = new APDU_Response (*data); + return apdu_resp; + } + } + + if (VerifyMAC (apdu) != 1) + { + Buffer data = Buffer (1, (BYTE) 0x6a) + Buffer (1, (BYTE) 0x88); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; + } +#if 0 + printf ("New PIN: \n"); + new_pin_buf.dump (); +#endif + + /* replace current pin */ + int i; + char *new_pin = (char *) malloc (new_pin_buf.size () + 1); + for (i = 0; i < (int) new_pin_buf.size (); i++) + { + new_pin[i] = ((BYTE *) new_pin_buf)[i]; + } + new_pin[new_pin_buf.size ()] = '\0'; + + if (m_pin != NULL) + { + PL_strfree (m_pin); + m_pin = NULL; + } + m_pin = new_pin; + + Buffer data = Buffer (1, (BYTE) 0x90) + Buffer (1, (BYTE) 0x00); + APDU_Response *apdu_resp = new APDU_Response (data); + return apdu_resp; +} + +APDU_Response * +RA_Token::Process (APDU * apdu, NameValueSet * vars, NameValueSet * params) +{ + APDU_Response *resp = NULL; + + if (apdu->GetType () == APDU_INITIALIZE_UPDATE) + { + resp = ProcessInitializeUpdate ((Initialize_Update_APDU *) apdu, vars, + params); + } + else if (apdu->GetType () == APDU_EXTERNAL_AUTHENTICATE) + { + resp = ProcessExternalAuthenticate ((External_Authenticate_APDU *) apdu, + vars, params); + } + else if (apdu->GetType () == APDU_SET_PIN) + { + resp = ProcessSetPin ((Set_Pin_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_LOAD_FILE) + { + resp = ProcessLoadFile ((Load_File_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_FORMAT_MUSCLE_APPLET) + { + resp = ProcessFormatMuscleApplet ((Format_Muscle_Applet_APDU *) apdu, + vars, params); + } + else if (apdu->GetType () == APDU_INSTALL_LOAD) + { + resp = ProcessInstallLoad ((Install_Load_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_INSTALL_APPLET) + { + resp = ProcessInstallApplet ((Install_Applet_APDU *) apdu, vars, + params); + } + else if (apdu->GetType () == APDU_DELETE_FILE) + { + resp = ProcessDeleteFile ((Delete_File_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_CREATE_OBJECT) + { + resp = ProcessCreateObject ((Create_Object_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_LIFECYCLE) + { + resp = ProcessLifecycle ((Lifecycle_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_READ_BUFFER) + { + resp = ProcessReadBuffer ((Read_Buffer_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_UNBLOCK_PIN) + { + resp = ProcessUnblockPin ((Unblock_Pin_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_LIST_OBJECTS) + { + resp = ProcessListObjects ((List_Objects_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_READ_OBJECT) + { + resp = ProcessReadObject ((Read_Object_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_WRITE_OBJECT) + { + resp = ProcessWriteBuffer ((Write_Object_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_SELECT) + { + resp = ProcessSelect ((Select_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_GET_VERSION) + { + resp = ProcessGetVersion ((Get_Version_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_PUT_KEY) + { + resp = ProcessPutKey ((Put_Key_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_GET_STATUS) + { + resp = ProcessGetStatus ((Get_Status_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_GET_ISSUERINFO) + { + resp = ProcessGetIssuerInfo ((Get_IssuerInfo_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_SET_ISSUERINFO) + { + resp = ProcessSetIssuerInfo ((Set_IssuerInfo_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_GET_DATA) + { + resp = ProcessGetData ((Get_Data_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_LIST_PINS) + { + resp = ProcessListPins ((List_Pins_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_CREATE_PIN) + { + resp = ProcessCreatePin ((Create_Pin_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_GENERATE_KEY) + { + resp = ProcessGenerateKey ((Generate_Key_APDU *) apdu, vars, params); + } + else if (apdu->GetType () == APDU_IMPORT_KEY_ENC) + { + resp = ProcessImportKeyEnc ((Import_Key_Enc_APDU *) apdu, vars, params); + } + else + { + printf ("RA_Token: Unknown APDU (%d)\n", apdu->GetType ()); + /* error */ + } + return resp; +} diff --git a/base/tps/tools/raclient/RA_Token.h b/base/tps/tools/raclient/RA_Token.h new file mode 100644 index 000000000..bf92e4e89 --- /dev/null +++ b/base/tps/tools/raclient/RA_Token.h @@ -0,0 +1,225 @@ +/* --- 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 --- + */ + +#ifndef RA_TOKEN_H +#define RA_TOKEN_H + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include <config.h> +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include "main/Buffer.h" +#include "main/NameValueSet.h" +#include "apdu/APDU_Response.h" +#include "apdu/APDU.h" +#include "apdu/Initialize_Update_APDU.h" +#include "apdu/External_Authenticate_APDU.h" +#include "apdu/Set_Pin_APDU.h" +#include "apdu/Get_Status_APDU.h" +#include "apdu/Create_Object_APDU.h" +#include "apdu/Lifecycle_APDU.h" +#include "apdu/Read_Buffer_APDU.h" +#include "apdu/Get_IssuerInfo_APDU.h" +#include "apdu/Set_IssuerInfo_APDU.h" +#include "apdu/Load_File_APDU.h" +#include "apdu/Format_Muscle_Applet_APDU.h" +#include "apdu/Install_Applet_APDU.h" +#include "apdu/Install_Load_APDU.h" +#include "apdu/Unblock_Pin_APDU.h" +#include "apdu/Write_Object_APDU.h" +#include "apdu/Read_Object_APDU.h" +#include "apdu/List_Pins_APDU.h" +#include "apdu/List_Objects_APDU.h" +#include "apdu/Create_Pin_APDU.h" +#include "apdu/Generate_Key_APDU.h" +#include "apdu/Select_APDU.h" +#include "apdu/Delete_File_APDU.h" +#include "apdu/Get_Version_APDU.h" +#include "apdu/Get_Data_APDU.h" +#include "apdu/Put_Key_APDU.h" +#include "apdu/Import_Key_APDU.h" +#include "apdu/Import_Key_Enc_APDU.h" + +typedef enum { + auth, + mac, + kek + } keyType; + +class RA_Token +{ + public: + RA_Token(); + ~RA_Token(); + public: + char *GetPIN(); + Buffer &GetAuthKey(); + Buffer &GetMacKey(); + Buffer &GetKekKey(); + Buffer &GetAppletVersion(); + void SetAppletVersion(Buffer &version); + Buffer &GetCUID(); + void SetCUID(Buffer &cuid); + Buffer &GetMSN(); + void SetMSN(Buffer &msn); + Buffer &GetKeyInfo(); + int GetMajorVersion(); + int GetMinorVersion(); + void SetKeyInfo(Buffer &key_info); + void SetAuthKey(Buffer &key); + void SetMacKey(Buffer &key); + void SetKekKey(Buffer &key); + void SetMajorVersion(int v); + void SetMinorVersion(int v); + BYTE GetLifeCycleState(); + public: + int VerifyMAC(APDU *apdu); + void ComputeAPDUMac(APDU *apdu, Buffer &new_mac); + PK11SymKey *CreateSessionKey(keyType keytype, + Buffer &card_challenge, + Buffer &host_challenge); + RA_Token *Clone(); + void decryptMsg(Buffer &in_data, Buffer &out_data); + PK11SymKey *GetEncSessionKey(); + public: + int NoOfCertificates(); + CERTCertificate *GetCertificate(int pos); + int NoOfPrivateKeys(); + SECKEYPrivateKey *GetPrivateKey(int pos); + public: + APDU_Response *Process(APDU *apdu, NameValueSet *vars, NameValueSet *params); + APDU_Response *ProcessInitializeUpdate( + Initialize_Update_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessExternalAuthenticate( + External_Authenticate_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessReadObject(Read_Object_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessListObjects(List_Objects_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessDeleteFile(Delete_File_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessSetPin(Set_Pin_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessInstallApplet(Install_Applet_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessInstallLoad(Install_Load_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessLoadFile(Load_File_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessFormatMuscleApplet(Format_Muscle_Applet_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessGetVersion(Get_Version_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessListPins(List_Pins_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessCreatePin(Create_Pin_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessGetData(Get_Data_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessGetStatus(Get_Status_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessCreateObject(Create_Object_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessLifecycle(Lifecycle_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessReadBuffer(Read_Buffer_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessUnblockPin(Unblock_Pin_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessGetIssuerInfo(Get_IssuerInfo_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessSetIssuerInfo(Set_IssuerInfo_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessWriteBuffer(Write_Object_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessGenerateKey(Generate_Key_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessImportKeyEnc(Import_Key_Enc_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessSelect(Select_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + APDU_Response *ProcessPutKey(Put_Key_APDU *apdu, + NameValueSet *vars, + NameValueSet *params); + public: + Buffer m_card_challenge; + Buffer m_host_challenge; + PK11SymKey *m_session_key; + PK11SymKey *m_enc_session_key; + Buffer m_icv; + Buffer m_cuid; + Buffer m_msn; + Buffer m_version; + Buffer m_key_info; + Buffer m_auth_key; + Buffer m_mac_key; + Buffer m_kek_key; + Buffer m_buffer; + BYTE m_lifecycle_state; + char *m_pin; + Buffer* m_object; + int m_major_version; + int m_minor_version; + int m_object_len; + int m_chunk_len; + char m_objectid[3]; +}; + +#endif /* RA_TOKEN_H */ diff --git a/base/tps/tools/raclient/enroll.tps b/base/tps/tools/raclient/enroll.tps new file mode 100644 index 000000000..08e40b6e1 --- /dev/null +++ b/base/tps/tools/raclient/enroll.tps @@ -0,0 +1,42 @@ +# --- 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 --- +# +######################################################## +# Description: +# This data file tests enrollment operation. +# +# Execution: +# tpsclient < enroll.test +# +######################################################## +op=var_set name=ra_host value=air +op=var_set name=ra_port value=8099 +op=var_set name=ra_uri value=/nk_service +# print original token status +op=token_set cuid=a00192030405060708c9 msn=01020304 app_ver=6FBBC105 key_info=0101 major_ver=0 minor_ver=0 +op=token_set auth_key=404142434445464748494a4b4c4d4e4f +op=token_set mac_key=404142434445464748494a4b4c4d4e4f +op=token_set kek_key=404142434445464748494a4b4c4d4e4f +op=token_status +#op=ra_enroll uid=test pwd=password new_pin=password +op=ra_enroll uid=sectest13 num_threads=1 pwd=home-boy new_pin=password +# print changed token status +op=token_status +op=exit diff --git a/base/tps/tools/raclient/enroll1.test b/base/tps/tools/raclient/enroll1.test new file mode 100644 index 000000000..fdd54f704 --- /dev/null +++ b/base/tps/tools/raclient/enroll1.test @@ -0,0 +1,43 @@ +# --- 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 --- +# +######################################################## +# Description: +# This data file tests enrollent. +# +# Execution: +# tpsclient < enroll.test +# +######################################################## +op=var_set name=ra_host value=air +op=var_set name=ra_port value=8000 +op=var_set name=ra_uri value=/nk_service +# print original token status +op=token_status +###set token params +op=token_set cuid=a00192030405060708c9 msn=01020304 app_ver=6FBBC105 key_info=0101 major_ver=0 minor_ver=0 +op=token_set auth_key=404142434445464748494a4b4c4d4e4f +op=token_set mac_key=404142434445464748494a4b4c4d4e4f +op=token_set kek_key=404142434445464748494a4b4c4d4e4f +op=token_status +op=ra_enroll uid=sectest13 pwd=home-boy new_pin=password +# print changed token status +op=token_status +op=exit diff --git a/base/tps/tools/raclient/format.tps b/base/tps/tools/raclient/format.tps new file mode 100644 index 000000000..f087a2d25 --- /dev/null +++ b/base/tps/tools/raclient/format.tps @@ -0,0 +1,45 @@ +# --- 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 --- +# +######################################################## +# Description: +# This data file tests token format operation. +# +# Execution: +# tpsclient < format.test +# +######################################################## +op=var_set name=ra_host value=air +op=var_set name=ra_port value=8000 +op=var_set name=ra_uri value=/nk_service +op=var_list +# print original token status +op=token_status +### set token params +op=token_set cuid=a00192030405060708c9 app_ver=6FBBC105 key_info=0101 +op=token_set auth_key=404142434445464748494a4b4c4d4e4f +op=token_set mac_key=404142434445464748494a4b4c4d4e4f +op=token_set kek_key=404142434445464748494a4b4c4d4e4f +op=token_status +## perform format operation +op=ra_format uid=test pwd=password num_threads=1 new_pin=password +# print changed token status +op=token_status +op=exit diff --git a/base/tps/tools/raclient/nt_enroll.test b/base/tps/tools/raclient/nt_enroll.test new file mode 100644 index 000000000..f4faf18fe --- /dev/null +++ b/base/tps/tools/raclient/nt_enroll.test @@ -0,0 +1,212 @@ +# --- 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 --- +# +######################################################## +# Description: +# This data file tests enrollment operation. +# +# Execution: +# tpsclient < enroll.test +# +######################################################## +op=var_set name=ra_host value=water +op=var_set name=ra_port value=7888 +op=var_set name=ra_uri value=/nk_service +######################################################## +# Possible return codes: +# +# General errors: +# 6400 - No specific diagnosis +# 6700 - Wrong length in Lc +# 6982 - Security status not satisfied +# 6985 - Conditions of use not satisified +# 6a86 - Incorrect P1 P2 +# 6d00 - Invalid instruction +# 6e00 - Invalid class +# +# Install Load errors: +# 6581 - Memory Failure +# 6a80 - Incorrect parameters in data field +# 6a84 - Not enough memory space +# 6a88 - Referenced data not found +# +# Delete errors: +# 6200 - Application has been logically deleted +# 6581 - Memory failure +# 6985 - Referenced data cannot be deleted +# 6a88 - Referenced data not found +# 6a82 - Application not found +# 6a80 - Incorrect values in command data +# +# Get Data errors: +# 6a88 - Referenced data not found +# +# Get Status errors: +# 6310 - More data available +# 6a88 - Referenced data not found +# 6a80 - Incorrect values in command data +# +# Load errors: +# 6581 - Memory failure +# 6a84 - Not enough memory space +# 6a86 - Incorrect P1/P2 +# 6985 - Conditions of use not satisified +######################################################## +# +######################################################## +# Negative Test Cases Testing: +# +# To enable the testing, you need to uncomment +# the following: +# +#op=var_set name=test_enable value=true +# +# Init Update APDU: +# +#op=var_set name=test_apdu_iu_return_enable value=true +#op=var_set name=test_apdu_iu_return value=6a88 +# +# External Authenticate APDU: +# +#op=var_set name=test_apdu_ea_return_enable value=true +#op=var_set name=test_apdu_ea_return value=6a88 +# +# Generate Key APDU: +# +#op=var_set name=test_apdu_gk_return_enable value=true +#op=var_set name=test_apdu_gk_return value=6a88 +# +# Create Object APDU: +# +#op=var_set name=test_apdu_co_return_enable value=true +#op=var_set name=test_apdu_co_return value=6a88 +# +# Life Cycle APDU: +# +#op=var_set name=test_apdu_lc_return_enable value=true +#op=var_set name=test_apdu_lc_return value=6a88 +# +# Delete File APDU: +# +#op=var_set name=test_apdu_df_return_enable value=true +#op=var_set name=test_apdu_df_return value=6a88 +# +# Install Applet APDU: +# +#op=var_set name=test_apdu_ia_return_enable value=true +#op=var_set name=test_apdu_ia_return value=6a88 +# +# Install Load APDU: +# +#op=var_set name=test_apdu_il_return_enable value=true +#op=var_set name=test_apdu_il_return value=6a88 +# +# Load File APDU: +# +#op=var_set name=test_apdu_lf_return_enable value=true +#op=var_set name=test_apdu_lf_return value=6a88 +# +# Select Applet APDU: +# +#op=var_set name=test_apdu_se_return_enable value=true +#op=var_set name=test_apdu_se_return value=6a88 +# +# List PINs APDU: +# +#op=var_set name=test_apdu_lp_return_enable value=true +#op=var_set name=test_apdu_lp_return value=6a88 +# +# Create PIN APDU: +# +#op=var_set name=test_apdu_cp_return_enable value=true +#op=var_set name=test_apdu_cp_return value=6a88 +# +# Get Version APDU: +# +#op=var_set name=test_apdu_gv_return_enable value=true +#op=var_set name=test_apdu_gv_return value=6a88 +# +# Get Data APDU: +#op=var_set name=test_apdu_gd_return_enable value=true +#op=var_set name=test_apdu_gd_return value=6a88 +# +# Get Status APDU: +# +#op=var_set name=test_apdu_gs_return_enable value=true +#op=var_set name=test_apdu_gs_return value=6a88 +# +# Put Key APDU: +# +#op=var_set name=test_apdu_pk_return_enable value=true +#op=var_set name=test_apdu_pk_return value=6a88 +# +# Import Key Enc APDU: +# +#op=var_set name=test_apdu_ik_return_enable value=true +#op=var_set name=test_apdu_ik_return value=6a88 +# +# Read Buffer APDU: +# +#op=var_set name=test_apdu_rb_return_enable value=true +#op=var_set name=test_apdu_rb_return value=6a88 +# +# Unblock PIN APDU: +# +#op=var_set name=test_apdu_up_return_enable value=true +#op=var_set name=test_apdu_up_return value=6a88 +# +# List Objects APDU: +# +#op=var_set name=test_apdu_lo_return_enable value=true +#op=var_set name=test_apdu_lo_return value=6a88 +# +# Read Object APDU: +# +#op=var_set name=test_apdu_ro_return_enable value=true +#op=var_set name=test_apdu_ro_return value=6a88 +# +# Write Buffer APDU: +# +#op=var_set name=test_apdu_wb_return_enable value=true +#op=var_set name=test_apdu_wb_return value=6a88 +# +# Set PIN APDU: +# +#op=var_set name=test_apdu_sp_return_enable value=true +#op=var_set name=test_apdu_sp_return value=6a88 +# +# ExtendedLoginRequest Message: +# +#op=var_set name=test_msg_el_resp_exclude_uid value=true +#op=var_set name=test_msg_el_resp_exclude_pwd value=true +#op=var_set name=test_msg_el_resp_add_invalid_param value=true +# +######################################################## +# print original token status +op=token_set cuid=a00192030405060708c9 msn=01020304 app_ver=6FBBC105 key_info=0101 major_ver=0 minor_ver=0 +op=token_set auth_key=404142434445464748494a4b4c4d4e4f +op=token_set mac_key=404142434445464748494a4b4c4d4e4f +op=token_set kek_key=404142434445464748494a4b4c4d4e4f +op=token_status +#op=ra_enroll uid=test pwd=password new_pin=password +op=ra_enroll uid=testuser1 num_threads=1 pwd=netscape new_pin=password +# print changed token status +op=token_status +op=exit diff --git a/base/tps/tools/raclient/readme.txt b/base/tps/tools/raclient/readme.txt new file mode 100644 index 000000000..8997544ac --- /dev/null +++ b/base/tps/tools/raclient/readme.txt @@ -0,0 +1,247 @@ +# --- 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 --- +# +Overview +======== + +tpsclient is a test utility that talks to the TPS +directly using HTTP protocol. + +It is a software-based token. It can be used as a driver +for stress/scalability testing. + +It can be used for the following operations: + + enrollment - This is for getting a certificate + into the token. + pin reset - This is for changing the token's pin. + format - This is for formatting the token to + remove the certificates from the token + and load fresh applets. + +Configuration +============= + +The tpsclient utility accepts a test script file. Each script +file contains a sequence of operations. Each operation +is composed of a set of name value pairs. For example, + + op=var_set name=ra_host value=familiar + +It starts with an operation type such as 'op=var_set' and +follows by a list of parameters as 'name=ra_host value=familiar'. + +The currently supported operation types are as follows: + + op=var_list - list all TPS connection parameters + op=var_get - retrieve the value of a TPS connection parameter + op=var_set - set the value of a TPS conection parameter + + op=exit - exit this utility + op=help - get more information about each operation + + op=token_status - list all token parameters + op=token_set - set the value of a token parameter + + op=ra_enroll - perform an enrollment operation + op=ra_reset_pin - perform a pin reset operation + op=ra_format - perform a format operation + +Configuration Examples +====================== + +Setup TPS's connection information: + + op=var_set name=ra_host value=familiar + op=var_set name=ra_port value=9003 + op=var_set name=ra_uri value=/nk_service + +Setup token's ID, Applet ID, and Key Set Version: + + op=token_set cuid=a00192030405060708c9 app_ver=6FBBC105 key_info=0101 + +Setup Key Data: (Note that '404142434445464748494a4b4c4d4e4f' is the +default key created by the manufacturer in the real token) + + op=token_set auth_key=404142434445464748494a4b4c4d4e4f + op=token_set mac_key=404142434445464748494a4b4c4d4e4f + op=token_set kek_key=404142434445464748494a4b4c4d4e4f + +Perform an enrollment operation: + + op=ra_enroll uid=sectest13 pwd=home-boy new_pin=password + +Perform a pin reset operation: + + op=ra_reset_pin uid=test pwd=password new_pin=newpassw + +Perform a format operation: + + op=ra_format uid=test pwd=password new_pin=newpassw + +Print the information inside token: + + op=token_status + +Applet Upgrade Example +====================== + +To test applet upgrade, you should first setup TPS to enable +applet upgrade. Please consult the TPS documentation for those +details. + +You should try to do an enrollment operation with an applet +version that's different from the one that's configured in +the TPS's configuration file. For example, you should have +the following in the test script. + + op=token_set cuid=18888883333300000004 app_ver=402428AD key_info=0101 + +This indicates that the token's applet version is currently at +40248AD. + + +After execution, you should see an audit event logged on the +TPS's audit log file like this, + + + ... + [2004-11-15 16:56:38] 847f220 Enrollment - op='applet_upgrade' + app_ver='0.0.402428AD' new_app_ver='1.2.416DA155' + ... + ... + [2004-11-15 16:56:43] 847f220 Enrollment - status='success' + app_ver='1.2.416DA155' key_ver='0101' cuid='18888883333300000004' + msn='00000000' uid='user1' auth='ldap1' time='7243 msec' + +Key Change Over Example +======================= + +To test key change over, you should setup a version 2 master key +in TKS and enable the key change over feature in TPS. Please +consult the TPS documentation for details. + +You should try to do an enrollment with a version 1 key in the +token. TPS should change the key in your token to +version 2. For example, you should have the following in +the test script: + + op=token_set cuid=a00192030405060708c9 app_ver=6FBBC105 key_info=0101 + op=token_set auth_key=404142434445464748494a4b4c4d4e4f + op=token_set mac_key=404142434445464748494a4b4c4d4e4f + op=token_set kek_key=404142434445464748494a4b4c4d4e4f + +Note 'key_info=0101' indicates a version 1 key set. + +After the execution, you should see the following in the output: + + ... + Output> cuid : 'a00192030405060708c9' (10 bytes) + Output> key_info : '0201' (2 bytes) + Output> auth_key : 'a3523ec8c0740b621e18e9cdd99f75fc' (16 bytes) + Output> mac_key : '903af964eb7ede26ea189243a5caad9c' (16 bytes) + Output> kek_key : '44ef9de3775121a871c152563d9b9860' (16 bytes) + ... + +'key_info: 0201' indicates that the current key set in the +token now changed from '0101' to '0201'. And as you noticed, +the key data for auth, mac, and kek keys are all different. + +If you check the TPS's log, you should see an audit event for +the key change over operation. + +After this, you should try to enroll with a version 2 keys. +For example, create a new test script that contains: + + op=token_set cuid=a00192030405060708c9 app_ver=6FBBC105 key_info=0201 + op=token_set auth_key=a3523ec8c0740b621e18e9cdd99f75fc + op=token_set mac_key=903af964eb7ede26ea189243a5caad9c + op=token_set kek_key=44ef9de3775121a871c152563d9b9860 + +Execute this test script, and you should NOT see an audit +event for key change over. It is because your token already +has a version 2 key set. + +You can also try to key change over from version 2 back to +version 1 with appropriate TPS configuration and test +script. + +Choose a specific profile in TPS +================================ + +TPS can be configured to support several profiles like + + 1) devicekey profile - used to issue only signing certs + 2) userKey profile - used to issue signing and encryption certs + +the tpsclient can be configured to tell TPS to select the right +profile by adding the following to the op=ra_enroll line in the +test script + + op=ra_enroll uid=user1 num_threads=1 pwd=password new_pin=newpassw + extensions=tokenType=userKey + + (OR) + + op=ra_enroll uid=user1 num_threads=1 pwd=password new_pin=newpassw + extensions=tokenType=deviceKey + +Stress test Example +=================== + +tpsclient can be configured to start multiple threads to perform +enrollment or pin reset or format operations, to stress the TPS +installation. + + op=ra_enroll uid=user1 num_threads=1 pwd=password new_pin=newpassw + extensions=tokenType=userKey + +In the above test script line, the num_threads parameter indicates +the number of threads that will be started. + +Also , to control the number of operations being performed, the +following parameter should be set in the test script line. + + op=ra_enroll uid=user1 num_threads=1 pwd=password new_pin=newpassw + extensions=tokenType=userKey max_ops=10 + +max_ops, indicates the number of operations that will be performed +by all the threads. + + + + +Execution +========= + +For Enrollment Operation: + + tpsclient < enroll.test + +For Reset Pin Operation: + + tpsclient < reset_pin.test + +Note +==== + +You may need to setup LD_LIBRARY_PATH (On Linux, and Solaris) to +point to the directory where you have NSPR, NSS, TPS shared libraries. + diff --git a/base/tps/tools/raclient/reset_pin.tps b/base/tps/tools/raclient/reset_pin.tps new file mode 100644 index 000000000..1a81fd2a7 --- /dev/null +++ b/base/tps/tools/raclient/reset_pin.tps @@ -0,0 +1,42 @@ +# --- 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 --- +# +######################################################## +# Description: +# This data file tests pin reset operation. +# +# Execution: +# tpsclient < reset_pin.test +# +######################################################## +op=var_set name=ra_host value=air +op=var_set name=ra_port value=8000 +op=var_set name=ra_uri value=/nk_service +op=var_list +# print original token status +op=token_set cuid=a00192030405060708c9 app_ver=6FBBC105 key_info=0101 +op=token_set auth_key=404142434445464748494a4b4c4d4e4f +op=token_set mac_key=404142434445464748494a4b4c4d4e4f +op=token_set kek_key=404142434445464748494a4b4c4d4e4f +op=token_status +op=ra_reset_pin uid=test pwd=password num_threads=1 new_pin=password +# print changed token status +op=token_status +op=exit diff --git a/base/tps/tools/raclient/reset_pin1.test b/base/tps/tools/raclient/reset_pin1.test new file mode 100644 index 000000000..2169e7ce2 --- /dev/null +++ b/base/tps/tools/raclient/reset_pin1.test @@ -0,0 +1,40 @@ +# --- 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 --- +# +######################################################## +# Description: +# This data file tests pin reset. +# +# Execution: +# tpsclient < reset_pin.test +# +# This one is failure case. The sectest12 requires securid but +# the test doesnt provide one. +######################################################## +op=var_set name=ra_host value=broom +op=var_set name=ra_port value=2020 +op=var_set name=ra_uri value=/nk_service +op=var_list +# print original token status +op=token_status +op=ra_reset_pin uid=sectest12 pwd=blue77 new_pin=password +# print changed token status +op=token_status +op=exit diff --git a/base/tps/tools/raclient/reset_pin2.test b/base/tps/tools/raclient/reset_pin2.test new file mode 100644 index 000000000..77b5d20d2 --- /dev/null +++ b/base/tps/tools/raclient/reset_pin2.test @@ -0,0 +1,39 @@ +# --- 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 --- +# +######################################################## +# Description: +# This data file tests pin reset. +# +# Execution: +# tpsclient < reset_pin.test +# +# This one is success case. The sectest13 does not require securid. +######################################################## +op=var_set name=ra_host value=broom +op=var_set name=ra_port value=2020 +op=var_set name=ra_uri value=/nk_service +op=var_list +# print original token status +op=token_status +op=ra_reset_pin uid=sectest13 pwd=home-boy new_pin=password +# print changed token status +op=token_status +op=exit diff --git a/base/tps/tools/tus/add.c b/base/tps/tools/tus/add.c new file mode 100644 index 000000000..f88ae9753 --- /dev/null +++ b/base/tps/tools/tus/add.c @@ -0,0 +1,117 @@ +/* --- 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 --- + */ + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include <config.h> +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include "nsapi.h" + +#include <time.h> +#include <stdlib.h> +#include <stdio.h> +#include "ldap.h" + +#include "tus/tus_db.h" + +/* Specify the search criteria here. */ +static char *host = "localhost"; +static int port = 389; +static char *baseDN = "ou=Tokens,dc=mcom,dc=com"; +static char *prefix = "0000"; +static char *suffix = "0000"; +static int start = 1; +static int len = 0; +static char *who = NULL; +static char *password = NULL; +static char *token_type = NULL; + + +#define SCOPE LDAP_SCOPE_SUBTREE +#define FILTER "(cn=*)" + +int main (int argc, char **argv) +{ + int i, h, rc; + char cn[256]; + char *errorMsg = NULL; + + if (argc < 9 || argc > 11) { + printf ("Usage:\n %s baseDN prefix suffix start len who password token_type host port", argv[0]); + return 1; + } + + baseDN = argv[1]; + prefix = argv[2]; + suffix = argv[3]; + start = atoi(argv[4]); + len = atoi(argv[5]); + who = argv[6]; + password = argv[7]; + token_type = argv[8]; + + if (argc > 9) { + host = argv[9]; + } + + if (argc > 10) { + port = atoi(argv[10]); + } + + set_tus_db_baseDN(baseDN); + set_tus_db_port(port); + set_tus_db_host(host); + set_tus_db_bindDN(who); + set_tus_db_bindPass(password); + rc = tus_db_init(errorMsg); + if (rc != LDAP_SUCCESS) { + fprintf(stderr, "tus_db_init: (%d) %s\n", rc, errorMsg); + return 1; + } + + for (i = 0; i < len; i++) { + h = start + i; + sprintf(cn, "%s%08X%s", prefix, h, suffix); + printf ("Adding %s\n", cn); + + rc = add_default_tus_db_entry (NULL, "", cn, "active", "", "", token_type); + if (rc != LDAP_SUCCESS) { + fprintf( stderr, "ldap_add_ext_s: %s\n", ldap_err2string( rc ) ); + return 1; + } + } + + /* STEP 4: Disconnect from the server. */ + tus_db_end(); + + return( 0 ); +} diff --git a/base/tps/tools/tus/test.c b/base/tps/tools/tus/test.c new file mode 100644 index 000000000..a307d1ccc --- /dev/null +++ b/base/tps/tools/tus/test.c @@ -0,0 +1,117 @@ +/* --- 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 --- + */ + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include <config.h> +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include "ldap.h" +#include "ldappr.h" + +/* Specify the search criteria here. */ +#define HOSTNAME "localhost" +#define PORTNUMBER 389 +#define BASEDN "ou=Tokens,dc=mcom,dc=com" +#define SCOPE LDAP_SCOPE_SUBTREE +#define FILTER "(cn=*)" + +int +main( int argc, char **argv ) +{ + char ldapuri[1024]; + LDAP *ld; + LDAPMessage *result = NULL, *e; + char *dn = NULL; + int version, rc; + /* Print out an informational message. */ + printf( "Connecting to host %s at port %d...\n\n", HOSTNAME, + PORTNUMBER ); + + /* STEP 1: Get a handle to an LDAP connection and + set any session preferences. */ + snprintf(ldapuri, 1024, "ldap://%s:%i", HOSTNAME, PORTNUMBER); + rc = ldap_initialize(&ld, ldapuri); + + if ( ld == NULL ) { + perror( "ldap_initialize" ); + return( 1 ); + } + + /* Use the LDAP_OPT_PROTOCOL_VERSION session preference to specify + that the client is an LDAPv3 client. */ + version = LDAP_VERSION3; + ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); + + /* STEP 2: Bind to the server. + In this example, the client binds anonymously to the server + (no DN or credentials are specified). */ + rc = ldap_sasl_bind_s(ld, NULL, LDAP_SASL_SIMPLE, NULL, NULL, NULL, NULL); + if ( rc != LDAP_SUCCESS ) { + fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc)); + return( 1 ); + } + + /* Print out an informational message. */ + printf( "Searching the directory for entries\n" + " starting from the base DN %s\n" + " within the scope %d\n" + " matching the search filter %s...\n\n", + BASEDN, SCOPE, FILTER ); + + /* STEP 3: Perform the LDAP operations. + In this example, a simple search operation is performed. + The client iterates through each of the entries returned and + prints out the DN of each entry. */ + rc = ldap_search_ext_s( ld, BASEDN, SCOPE, FILTER, NULL, 0, + NULL, NULL, NULL, 0, &result ); + if ( rc != LDAP_SUCCESS ) { + fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(rc)); + return( 1 ); + } + for ( e = ldap_first_entry( ld, result ); e != NULL; + e = ldap_next_entry( ld, e ) ) { + if ( (dn = ldap_get_dn( ld, e )) != NULL ) { + printf( "dn: %s\n", dn ); + ldap_memfree( dn ); + dn = NULL; + } + } + if( result != NULL ) { + ldap_msgfree( result ); + result = NULL; + } + + /* STEP 4: Disconnect from the server. */ + ldap_unbind_ext_s( ld, NULL, NULL ); + return( 0 ); +} |