/*
* Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace Tizen.Network.Smartcard
{
///
/// A class for Smartcard session informations. It allows applications to handle session informations.
///
/// 3
/// http://tizen.org/privilege/secureelement
public class SmartcardSession : IDisposable
{
private int _sessionHandle = -1;
private bool disposed = false;
private List _basicChannelList = new List();
private List _logicalChannelList = new List();
private SmartcardReader _readerObject;
private int _basicChannel = 0;
private int _logicalChannel = 0;
///
/// The reader object that provides the given session.
///
/// 3
public SmartcardReader Reader
{
get
{
int reader;
int ret = Interop.Smartcard.Session.SessionGetReader(_sessionHandle, out reader);
if (ret != (int)SmartcardError.None)
{
Log.Error(Globals.LogTag, "Failed to get reader, Error - " + (SmartcardError)ret);
}
if (_readerObject.GetHandle() != reader)
{
Log.Error(Globals.LogTag, "Does not correspond with reader, Error - " + _readerObject.GetHandle() + " " + reader);
}
return _readerObject;
}
}
///
/// The Answer to Reset(ATR) of this Secure Element.
///
/// 3
public byte[] Atr
{
get
{
byte[] atrList;
IntPtr strAtr;
int len;
int ret = Interop.Smartcard.Session.SessionGetAtr(_sessionHandle, out strAtr, out len);
if (ret != (int)SmartcardError.None)
{
Log.Error(Globals.LogTag, "Failed to get atr, Error - " + (SmartcardError)ret);
}
atrList = new byte[len];
for (int i = 0; i < len; i++)
{
atrList[i] = Marshal.ReadByte(strAtr);
strAtr += sizeof(byte);
}
return atrList;
}
}
///
/// Whether the session is closed.
///
/// 3
public bool IsClosed
{
get
{
bool isClosed;
int ret = Interop.Smartcard.Session.SessionIsClosed(_sessionHandle, out isClosed);
if (ret != (int)SmartcardError.None)
{
Log.Error(Globals.LogTag, "Failed to get present, Error - " + (SmartcardError)ret);
}
return isClosed;
}
}
internal SmartcardSession(SmartcardReader readerHandle, int sessionHandle)
{
_readerObject = readerHandle;
_sessionHandle = sessionHandle;
}
~SmartcardSession()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
// Free managed objects.
foreach (SmartcardChannel channel in _basicChannelList)
{
channel.Dispose();
_basicChannelList.Remove(channel);
}
foreach (SmartcardChannel channel in _logicalChannelList)
{
channel.Dispose();
_logicalChannelList.Remove(channel);
}
}
//Free unmanaged objects
disposed = true;
}
internal int GetHandle()
{
return _sessionHandle;
}
///
/// Closes the connection with the Secure Element.
///
/// 3
/// Thrown when Smartcard is not supported.
/// Thrown when the method failed due to invalid operation.
public void Close()
{
int ret = Interop.Smartcard.Session.SessionClose(_sessionHandle);
if (ret != (int)SmartcardError.None)
{
Log.Error(Globals.LogTag, "Failed to close, Error - " + (SmartcardError)ret);
SmartcardErrorFactory.ThrowSmartcardException(ret);
}
Dispose(true);
}
///
/// Closes any channel opened on the given session.
///
/// 3
/// Thrown when Smartcard is not supported.
/// Thrown when the method failed due to invalid operation.
public void CloseChannels()
{
int ret = Interop.Smartcard.Session.SessionCloseChannels(_sessionHandle);
if (ret != (int)SmartcardError.None)
{
Log.Error(Globals.LogTag, "Failed to close, Error - " + (SmartcardError)ret);
SmartcardErrorFactory.ThrowSmartcardException(ret);
}
foreach (SmartcardChannel channel in _basicChannelList)
{
channel.Close();
}
foreach (SmartcardChannel channel in _logicalChannelList)
{
channel.Close();
}
}
///
/// Gets an access to the basic channel, as defined in the ISO/IEC 7816-4 specification (the one that has number 0).
///
/// 3
/// The SmartcardChannel object for basic channel.
/// Byte array containing the Application ID(AID) to be selected on the given channel.
/// P2 byte of the SELECT command if executed.
/// Thrown when Smartcard is not supported.
/// Thrown when the method failed due to invalid operation.
public SmartcardChannel OpenBasicChannel(byte[] aid, byte p2)
{
int ret = Interop.Smartcard.Session.SessionOpenBasicChannel(_sessionHandle, aid, aid.Length, p2, out _basicChannel);
if (ret != (int)SmartcardError.None)
{
Log.Error(Globals.LogTag, "Failed to open basic channel, Error - " + (SmartcardError)ret);
SmartcardErrorFactory.ThrowSmartcardException(ret);
}
SmartcardChannel basicChannel = new SmartcardChannel(this, _basicChannel);
_basicChannelList.Add(basicChannel);
return basicChannel;
}
///
/// Open a logical channel with the Secure Element, selecting the Applet represented by the given Application ID(AID).
///
/// 3
/// The SmartcardChannel object for logical channel.
/// Byte array containing the Application ID(AID) to be selected on the given channel.
/// P2 byte of the SELECT command if executed.
/// Thrown when Smartcard is not supported.
/// Thrown when the method failed due to invalid operation.
public SmartcardChannel OpenLogicalChannel(byte[] aid, byte p2)
{
int ret = Interop.Smartcard.Session.SessionOpenLogicalChannel(_sessionHandle, aid, aid.Length, p2, out _logicalChannel);
if (ret != (int)SmartcardError.None)
{
Log.Error(Globals.LogTag, "Failed to open logical channel, Error - " + (SmartcardError)ret);
SmartcardErrorFactory.ThrowSmartcardException(ret);
}
SmartcardChannel logicalChannel = new SmartcardChannel(this, _logicalChannel);
_logicalChannelList.Add(logicalChannel);
return logicalChannel;
}
}
}