diff options
Diffstat (limited to 'base/tps/tools/raclient/RA_Conn.cpp')
-rw-r--r-- | base/tps/tools/raclient/RA_Conn.cpp | 1037 |
1 files changed, 1037 insertions, 0 deletions
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; +} |