NTSTATUS CBTransmit( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBTransmit: callback handler for SMCLIB RDF_TRANSMIT Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_INVALID_DEVICE_REQUEST --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBTransmit: Enter\n" ) ); // dispatch on the selected protocol switch ( SmartcardExtension->CardCapabilities.Protocol.Selected ) { case SCARD_PROTOCOL_T0: NTStatus = CBT0Transmit( SmartcardExtension ); break; case SCARD_PROTOCOL_T1: NTStatus = CBT1Transmit( SmartcardExtension ); break; case SCARD_PROTOCOL_RAW: NTStatus = CBRawTransmit( SmartcardExtension ); break; default: NTStatus = STATUS_INVALID_DEVICE_REQUEST; break; } SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBTransmit: Exit (%lx)\n", NTStatus ) ); return( NTStatus ); }
/** * @brief Transmission by T=0 TPDU Mode * @param portno Indicate which port to open (0:Port0; 1:Port1) * @param pBlockBuffer Command Data * @param pBlockSize The size of command data * @retval Slot Status Error Code */ unsigned char Ifd_XfrTpduT0(int32_t portno, unsigned char *pBlockBuffer, unsigned int *pBlockSize ) { int32_t ErrorCode; uint8_t rbuf[MIN_BUFFER_SIZE]; uint32_t idx, AnswerSize, rlen; S_SC_DEV_T *dev; dev = (S_SC_DEV_T *)((uint32_t)&sc_device[portno]); if( *pBlockBuffer == 0xFF ) /* PPS Exchange Process */ { AnswerSize = 4; ErrorCode = CBRawTransmit( dev, pBlockBuffer, *pBlockSize, AnswerSize, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // received data for(idx=0; idx<rlen; idx++) { *pBlockBuffer = rbuf[idx]; pBlockBuffer++; } // length of received data *pBlockSize = rlen; } else { ErrorCode = CBT0Transmit( dev, pBlockBuffer, *pBlockSize, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // received data for(idx=0; idx<rlen; idx++) { *pBlockBuffer = rbuf[idx]; pBlockBuffer++; } // length of received data *pBlockSize = rlen; } return SLOT_NO_ERROR; }
NTSTATUS CBRawTransmit( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBRawTransmit: finishes the callback RDF_TRANSMIT for the RAW protocol Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_INVALID_DEVICE_REQUEST --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR TLVList[ TLV_BUFFER_SIZE ], Val, Len; ULONG TLVListLen; PREADER_EXTENSION ReaderExtension; SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBRawTransmit: Enter\n" ) ); ReaderExtension = SmartcardExtension->ReaderExtension; // // read the status file of ICC1 from the reader // TLVListLen = TLV_BUFFER_SIZE; NTStatus = CmdReadStatusFile( ReaderExtension, ReaderExtension->Device, TLVList, &TLVListLen ); // // check the active protocol of the reader // if ( NT_SUCCESS( NTStatus )) { Len = sizeof(Val); NTStatus = CmdGetTagValue( TAG_ICC_PROTOCOLS, TLVList, TLVListLen, &Len, ( PVOID ) &Val ); // execute the active protocol if ( NT_SUCCESS( NTStatus )) { // translate the actual protocol to a value the lib can understand switch ( Val ) { case PSCR_PROTOCOL_T0: NTStatus = CBT0Transmit( SmartcardExtension ); break; case PSCR_PROTOCOL_T1: NTStatus = CBT1Transmit( SmartcardExtension ); break; default: NTStatus = STATUS_UNSUCCESSFUL; break; } } } SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBRawTransmit: Exit (%lx)\n", NTStatus ) ); return( NTStatus ); }
/** * @brief Transmission by T=0 Extend APDU Mode * @param portno Indicate which port to open (0:Port0; 1:Port1) * @param pBlockBuffer Command Data * @param pBlockSize The size of command data * @retval Slot Status Error Code */ unsigned char Ifd_XfrExtendApduT0( int32_t portno, unsigned char *pBlockBuffer, unsigned int *pBlockSize ) { int32_t ErrorCode, idx; uint8_t rbuf[MIN_BUFFER_SIZE]; uint32_t datalength, rlen; S_SC_DEV_T *dev; unsigned char getresponsebuf[5]; unsigned char envelopebuf[300]; // 255 bytes + 5 command data dev = (S_SC_DEV_T *)((uint32_t)&sc_device[portno]); if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x01) { datalength = (*pBlockSize) - 7; pBlockBuffer = pBlockBuffer + 7; while(datalength) { envelopebuf[0] = USB_ConfigDescriptor[49+18]; // CLA = bClassEnvelope field envelopebuf[1] = 0xC2; // 0xC2 = Envelope command envelopebuf[2] = 0x00; // 0x00 envelopebuf[3] = 0x00; // 0x00 if(datalength >= 0xFF) envelopebuf[4] = 0xFF; // APDU length > buffer length else envelopebuf[4] = datalength; // APDU length > buffer length if(datalength >= 0xFF) { for(idx=0; idx < 0xFF; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; } else { for(idx=0; idx < datalength; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; } if(datalength >= 0xFF) ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+0xFF, &rbuf[0], &rlen); else ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+datalength, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); if(datalength >= 0xFF) { pBlockBuffer+=0xFF; datalength-=0xFF; } else datalength-=datalength; } // length of received data *pBlockSize = 0; // Chain Parameter Setting g_ChainParameter = 0x10; } else if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x02) { datalength = (*pBlockSize) - 7; pBlockBuffer = pBlockBuffer + 7; envelopebuf[0] = USB_ConfigDescriptor[49+18]; // CLA = bClassEnvelope field envelopebuf[1] = 0xC2; // 0xC2 = Envelope command envelopebuf[2] = 0x00; // 0x00 envelopebuf[3] = 0x00; // 0x00 envelopebuf[4] = datalength; // last part of APDU command for(idx=0; idx < datalength; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+envelopebuf[4], &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // get response command getresponsebuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field getresponsebuf[1] = 0xC0; // 0xC0 = Get response command getresponsebuf[2] = 0x00; // 0x00 getresponsebuf[3] = 0x00; // 0x00 getresponsebuf[4] = 0x00; // 0x00 ErrorCode = CBT0Transmit( dev, &getresponsebuf[0], 0x5, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // check if data bytes still available, max. size of buffer is 500 bytes //while(1) //{ if((rlen==2) && (rbuf[0]==0x61)) { getresponsebuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field getresponsebuf[1] = 0xC0; // 0xC0 == Get response command getresponsebuf[2] = 0x00; // 0x00 getresponsebuf[3] = 0x00; // 0x00 getresponsebuf[4] = rbuf[1]; // Licc = how many data bytes still available if(getresponsebuf[4]==0xFF) // TODO: care this point. NOT sure how to handle this ErrorCode = CBRawTransmit( dev, &getresponsebuf[0], 0x5, 0xFF, &rbuf[0], &rlen); else { ErrorCode = CBT0Transmit( dev, &getresponsebuf[0], 0x5, &rbuf[0], &rlen); printf("why available data is less than 0xff \n"); } if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); } //} // store received data pBlockBuffer = pBlockBuffer - 7; for(idx=0; idx<rlen; idx++) pBlockBuffer[idx] = rbuf[idx]; // length of received data *pBlockSize = getresponsebuf[4]; // Chain Parameter Setting g_ChainParameter = 0x01; } else if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x03) { datalength = (*pBlockSize) - 7; pBlockBuffer = pBlockBuffer + 7; while(datalength) { envelopebuf[0] = USB_ConfigDescriptor[49+18]; // CLA = bClassEnvelope field envelopebuf[1] = 0xC2; // 0xC2 = Envelope command envelopebuf[2] = 0x00; // 0x00 envelopebuf[3] = 0x00; // 0x00 if(datalength >= 0xFF) envelopebuf[4] = 0xFF; // APDU length > buffer length else envelopebuf[4] = datalength; // APDU length > buffer length if(datalength >= 0xFF) { for(idx=0; idx < 0xFF; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; } else { for(idx=0; idx < datalength; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; } if(datalength >= 0xFF) ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+0xFF, &rbuf[0], &rlen); else ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+datalength, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); if(datalength >= 0xFF) { pBlockBuffer+=0xFF; datalength-=0xFF; } else datalength-=datalength; } // length of received data *pBlockSize = 0; // Chain Parameter Setting g_ChainParameter = 0x10; } else if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x10) { // get response command getresponsebuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field getresponsebuf[1] = 0xC0; // 0xC0 = Get response command getresponsebuf[2] = 0x00; // 0x00 getresponsebuf[3] = 0x00; // 0x00 getresponsebuf[4] = 0x00; // 0x00 ErrorCode = CBT0Transmit( dev, &getresponsebuf[0], 0x5, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // check if data bytes still available, max. size of buffer is 500 bytes if((rlen==2) && (rbuf[0]==0x61)) { getresponsebuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field getresponsebuf[1] = 0xC0; // 0xC0 == Get response command getresponsebuf[2] = 0x00; // 0x00 getresponsebuf[3] = 0x00; // 0x00 getresponsebuf[4] = rbuf[1]; // Licc = how many data bytes still available if(getresponsebuf[4]==0xFF) ErrorCode = CBRawTransmit( dev, &getresponsebuf[0], 0x5, 0xFF, &rbuf[0], &rlen); else ErrorCode = CBT0Transmit( dev, &getresponsebuf[0], 0x5, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); } // store received data for(idx=0; idx<rlen; idx++) pBlockBuffer[idx] = rbuf[idx]; // length of received data if(getresponsebuf[4]==0xFF) *pBlockSize = getresponsebuf[4]; else *pBlockSize = rlen; // Chain Parameter Setting if(getresponsebuf[4]==0xFF) g_ChainParameter = 0x03; else g_ChainParameter = 0x02; } return SLOT_NO_ERROR; }
/** * @brief Transmission by T=0 Short APDU Mode * @param portno Indicate which port to open (0:Port0; 1:Port1) * @param pBlockBuffer Command Data * @param pBlockSize The size of command data * @retval Slot Status Error Code */ unsigned char Ifd_XfrShortApduT0( int32_t portno, unsigned char *pBlockBuffer, unsigned int *pBlockSize ) { //uint8_t case_no=0x00; int32_t ErrorCode; uint8_t rbuf[MIN_BUFFER_SIZE]; uint8_t rbufICC[MIN_BUFFER_SIZE]; uint8_t *buf = rbuf; uint32_t idx, rlen, rlenICC; S_SC_DEV_T *dev; unsigned char blockbuf[5]; dev = (S_SC_DEV_T *)((uint32_t)&sc_device[portno]); //case_no = Ifd_CheckCmdCase(pBlockBuffer, *pBlockSize); CCIDSCDEBUG("Ifd_XfrShortApduT0: header=%02x %02x %02x %02x, len=%d\n", pBlockBuffer[0], pBlockBuffer[1], pBlockBuffer[2], pBlockBuffer[3], *pBlockSize); if( *pBlockSize == 0x4 ) { blockbuf[0] = pBlockBuffer[0]; blockbuf[1] = pBlockBuffer[1]; blockbuf[2] = pBlockBuffer[2]; blockbuf[3] = pBlockBuffer[3]; blockbuf[4] = 0x00; ErrorCode = CBT0Transmit( dev, &blockbuf[0], 0x5, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // received data for(idx=0; idx<rlen; idx++) { *pBlockBuffer = rbuf[idx]; pBlockBuffer++; } // length of received data *pBlockSize = rlen; } else { ErrorCode = CBT0Transmit( dev, pBlockBuffer, *pBlockSize, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // check if wrong Le field error while((rlen==2) && (rbuf[0]==0x6C)) { pBlockBuffer[4] = rbuf[1]; ErrorCode = CBT0Transmit( dev, pBlockBuffer, *pBlockSize, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); } // check if data bytes still available if((rlen==2) && (rbuf[0]==0x61)) { rlenICC = 0; while(1) { blockbuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field blockbuf[1] = 0xC0; // 0xC0 == Get response command blockbuf[2] = 0x00; // 0x00 blockbuf[3] = 0x00; // 0x00 blockbuf[4] = rbuf[rlen-1]; // Licc = how many data bytes still available ErrorCode = CBT0Transmit( dev, blockbuf, 0x5, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // received data if(rbuf[rlen-2]==0x61) { for(idx=0; idx<rlen-2; idx++) rbufICC[rlenICC++] = rbuf[idx]; } else { for(idx=0; idx<rlen; idx++) rbufICC[rlenICC++] = rbuf[idx]; } if(rbuf[rlen-2] != 0x61) break; } rlen = rlenICC; buf = rbufICC; } CCIDSCDEBUG("Ifd_XfrShortApduT0: dwLength = %d, Data = ", rlen); /* Check status bytes */ if((buf[rlen-2]&0xF0)!=0x60 && (buf[rlen-2]&0xF0)!=0x90) return SLOTERR_ICC_PROTOCOL_NOT_SUPPORTED; // received data for(idx=0; idx<rlen; idx++) { CCIDSCDEBUG("%02x", buf[idx]); *pBlockBuffer = buf[idx]; pBlockBuffer++; } CCIDSCDEBUG("\n"); // length of received data *pBlockSize = rlen; } return SLOT_NO_ERROR; }