作者归档:softsim

mtk Helio A22音频驱动

Helio A22

/dev/snd

pcmC0D10p pcmC0D14p pcmC0D17p pcmC0D1c  pcmC0D23p pcmC0D26c pcmC0D28p pcmC0D30c pcmC0D32c pcmC0D5c pcmC0D7p sequencer  
pcmC0D11p pcmC0D15c pcmC0D18c pcmC0D20p pcmC0D24p pcmC0D26p pcmC0D29p pcmC0D30p pcmC0D3c  pcmC0D5p pcmC0D8p sequencer2 
controlC0 pcmC0D12c pcmC0D16c pcmC0D18p pcmC0D21p pcmC0D25c pcmC0D27c pcmC0D2c  pcmC0D31c pcmC0D3p  pcmC0D6c pcmC0D9c timer      
pcmC0D0p  pcmC0D13c pcmC0D17c pcmC0D19p pcmC0D22c pcmC0D25p pcmC0D28c pcmC0D2p  pcmC0D31p pcmC0D4p  pcmC0D6p seq  

/vendor/lib/hw/audio.primary.mt6765.so
setBGSDlMute
setBGSUlMute

platform/common/hardware/audio/V3/aud_drv/AudioALSAHardware.cpp

...
// Set BGS Mute
static String8 keySet_BGS_DL_Mute = String8("Set_BGS_DL_Mute");
static String8 keySet_BGS_UL_Mute    = String8("Set_BGS_UL_Mute");
// Set Phone Call Mute
static String8 keySet_SpeechCall_DL_Mute = String8("Set_SpeechCall_DL_Mute");
static String8 keySet_SpeechCall_UL_Mute = String8("Set_SpeechCall_UL_Mute");

...


    // Set BGS DL Mute (true) / Unmute(false)
    if (param.getInt(keySet_BGS_DL_Mute, value) == NO_ERROR)
    {
        param.remove(keySet_BGS_DL_Mute);
        ALOGD("%s(), %s", __FUNCTION__, keyValuePairs.string());
        mStreamManager->setBGSDlMute((bool)value);
    }

    // Set BGS UL Mute (true) / Unmute(false)
    if (param.getInt(keySet_BGS_UL_Mute, value) == NO_ERROR)
    {
        param.remove(keySet_BGS_UL_Mute);
        ALOGD("%s(), %s", __FUNCTION__, keyValuePairs.string());
        mStreamManager->setBGSUlMute((bool)value);
    }

    // Set SpeechCall DL Mute (true) / Unmute(false)
    if (param.getInt(keySet_SpeechCall_DL_Mute, value) == NO_ERROR)
    {
        param.remove(keySet_SpeechCall_DL_Mute);
        ALOGD("%s(), %s", __FUNCTION__, keyValuePairs.string());
        mSpeechPhoneCallController->setDlMute((bool)value);
    }

    // Set SpeechCall UL Mute (true) / Unmute(false)
    if (param.getInt(keySet_SpeechCall_UL_Mute, value) == NO_ERROR)
    {
        param.remove(keySet_SpeechCall_UL_Mute);
        ALOGD("%s(), %s", __FUNCTION__, keyValuePairs.string());
        mSpeechPhoneCallController->setUlMute((bool)value);
    }

platform/mt6735/hardware/audio/aud_drv/AudioALSAStreamOut.cpp

开启通话背景音:
  Set_BGS_UL_Mute=0 关闭背景音上行的静音, 也就是让对方能听到
  Set_SpeechCall_UL_Mute=1 打开mic上行的静音, 也就是让对方听不到这边mic的声音
  Set_BGS_DL_Mute=1 开启背景音下行静音, 让自己听不到背景音

platform/mt6735/hardware/audio/aud_drv/AudioALSAStreamManager.cpp


AudioALSAStreamManager::AudioALSAStreamManager() :
    mStreamOutIndex(0),
    mStreamInIndex(0),
    mPlaybackHandlerIndex(0),
    mCaptureHandlerIndex(0),
    mSpeechPhoneCallController(AudioALSASpeechPhoneCallController::getInstance()),
    mFMController(AudioALSAFMController::getInstance()),
    mAudioALSAVolumeController(AudioVolumeFactory::CreateAudioVolumeController()),
    mSpeechDriverFactory(SpeechDriverFactory::GetInstance()),
    mAudioSpeechEnhanceInfoInstance(AudioSpeechEnhanceInfo::getInstance()),
    mMicMute(false),
    mAudioMode(AUDIO_MODE_NORMAL),
    mFilterManagerNumber(0),
    mBesLoudnessStatus(false),
    mBesLoudnessControlCallback(NULL),
//#ifdef MTK_VOW_SUPPORT  
    mAudioALSAVoiceWakeUpController(AudioALSAVoiceWakeUpController::getInstance()),
//#endif   
    mVoiceWakeUpNeedOn(false),
    mForceDisableVoiceWakeUpForSetMode(false),
    mBypassPostProcessDL(false),
    mHeadsetChange(false),
    mBGSDlGain(0xFF),
    mBGSUlGain(0),
    mBypassDualMICProcessUL(false)
{

....

mBGSDlGain 下行增益, 影响到 自己这边听到的声音大小, 最大值是0xFF(256),
mBGSUlGain 上行增益, 影响到 对方听到的声音大小, 最小值是0

所以,默认设置是 自己听得到, 对方听不到

status_t AudioALSAStreamManager::setBGSDlMute(const bool mute_on)
{
    if (mute_on)
    {
        mBGSDlGain = 0;
    }
    else
    {
        mBGSDlGain = 0xFF;
    }
    ALOGD("%s(), mute_on: %d, mBGSDlGain=0x%x", __FUNCTION__, mute_on, mBGSDlGain);

    return NO_ERROR;
}

...

status_t AudioALSAStreamManager::setBGSUlMute(const bool mute_on)
{
    if (mute_on)
    {
        mBGSUlGain = 0;
    }
    else
    {
        mBGSUlGain = 0xFF;
    }
    ALOGD("%s(), mute_on: %d, mBGSUlGain=0x%x", __FUNCTION__, mute_on, mBGSUlGain);

    return NO_ERROR;
}


可以通过 setBGSDlMute 函数来设置 mBGSDlGain变量的大小

hardware/audio/speech_driver/AudioALSASpeechPhoneCallController.cpp


void AudioALSASpeechPhoneCallController::setDlMute(const bool mute_on)
{

    ALOGD("%s(), new mute_on = %d, old mDlMute = %d", __FUNCTION__, mute_on, mDlMute);
    AudioAutoTimeoutLock _l(mLock);

    mSpeechDriverFactory->GetSpeechDriver()->SetDownlinkMute(mute_on);

    property_set(PROPERTY_KEY_DL_MUTE_ON, (mute_on == false) ? "0" : "1");
    mDlMute = mute_on;
}

void AudioALSASpeechPhoneCallController::setUlMute(const bool mute_on)
{
    ALOGD("+%s(), new mute_on = %d, old mULMute = %d", __FUNCTION__, mute_on, mUlMute);
    AudioAutoTimeoutLock _l(mLock);

    mSpeechDriverFactory->GetSpeechDriver()->SetUplinkSourceMute(mute_on);

    property_set(PROPERTY_KEY_UL_MUTE_ON, (mute_on == false) ? "0" : "1");
    mUlMute = mute_on;
}


 

platform/common/hardware/audio/V3/aud_drv/AudioALSAPlaybackHandlerVoice.cpp


...
status_t AudioALSAPlaybackHandlerVoice::open()
{
    ALOGD("+%s(), audio_mode = %d, u8BGSUlGain = %d, u8BGSDlGain = %d", __FUNCTION__, mStreamAttributeSource->audio_mode, mStreamAttributeSource->u8BGSUlGain, mStreamAttributeSource->u8BGSDlGain);

    ALOGD("%s() mStreamAttributeSource->audio_format =%d", __FUNCTION__,mStreamAttributeSource->audio_format);

    // debug pcm dump
    OpenPCMDump(LOG_TAG);


    // HW attribute config // TODO(Harvey): query this
    mStreamAttributeTarget.audio_format = AUDIO_FORMAT_PCM_16_BIT;
    mStreamAttributeTarget.audio_channel_mask = mStreamAttributeSource->audio_channel_mask; // same as source stream
    mStreamAttributeTarget.num_channels = android_audio_legacy::AudioSystem::popCount(mStreamAttributeTarget.audio_channel_mask);
    mStreamAttributeTarget.sample_rate = ChooseTargetSampleRate(mStreamAttributeSource->sample_rate); // same as source stream
    ALOGD("mStreamAttributeTarget sample_rate = %d mStreamAttributeSource sample_rate = %d",mStreamAttributeTarget.sample_rate,mStreamAttributeSource->sample_rate);
    mStreamAttributeTarget.u8BGSDlGain = mStreamAttributeSource->u8BGSDlGain;
    mStreamAttributeTarget.u8BGSUlGain = mStreamAttributeSource->u8BGSUlGain;

    // bit conversion
    initBitConverter();


    // open background sound
    mBGSPlayer->mBGSMutex.lock();

    if (mStreamAttributeTarget.num_channels > 2)
    {
        mBGSPlayer->CreateBGSPlayBuffer(
            mStreamAttributeTarget.sample_rate,
            2,
            mStreamAttributeTarget.audio_format);

    }
    else
    {
        mBGSPlayer->CreateBGSPlayBuffer(
            mStreamAttributeTarget.sample_rate,
            mStreamAttributeTarget.num_channels,
            mStreamAttributeTarget.audio_format);
    }
    mBGSPlayer->Open(SpeechDriverFactory::GetInstance()->GetSpeechDriver(), mStreamAttributeTarget.u8BGSUlGain, mStreamAttributeTarget.u8BGSDlGain);

    mBGSPlayer->mBGSMutex.unlock();

    ALOGD("-%s()", __FUNCTION__);
    return NO_ERROR;
}
....


可以看到 上下行增益 怎么传递过来的

mtk通话背景音

vendor/mediatek/proprietary/platform/common/hardware/audio/V3/aud_drv/AudioALSAPlaybackHandlerVoice.cpp

vendor/mediatek/proprietary/platform/common/hardware/audio/V3/speech_driver/SpeechMessengerEVDO.cpp

vendor/mediatek/proprietary/platform/common/hardware/audio/V3/speech_driver/SpeechMessengerDSDA.cpp

vendor/mediatek/proprietary/platform/common/hardware/audio/V3/speech_driver/SpeechMessengerECCCI.cpp

vendor/mediatek/proprietary/platform/common/hardware/audio/V2/speech_driver/SpeechMessengerCCCI.cpp

vendor/mediatek/proprietary/platform/common/hardware/audio/V2/speech_driver/SpeechMessengerEEMCS.cpp

vendor/mediatek/proprietary/platform/common/hardware/audio/speech_driver/SpeechBGSPlayer.cpp

vendor/mediatek/proprietary/platform/mt6735/hardware/audio/speech_driver/AudioALSASpeechPhoneCallController.cpp

vendor/mediatek/proprietary/platform/common/hardware/audio/V3/include/SpeechMessengerDSDA.h

vendor/mediatek/proprietary/platform/common/hardware/audio/V3/include/SpeechMessengerECCCI.h

vendor/mediatek/proprietary/platform/common/hardware/audio/V3/include/AudioALSAPlaybackHandlerVoice.h

vendor/mediatek/proprietary/platform/common/hardware/audio/V2/include/SpeechMessengerCCCI.h

vendor/mediatek/proprietary/platform/common/hardware/audio/include/SpeechBGSPlayer.h

vendor/mediatek/proprietary/platform/common/hardware/audio/include/SpeechMessengerInterface.h

———————

vendor/mediatek/proprietary/platform/mt6735/hardware/audio/aud_drv/AudioALSAStreamOut.cpp

status_t AudioALSAStreamOut::setParameters(const String8 &keyValuePairs)

高通音频控制接口

https://source.codeaurora.org/quic/la//kernel/msm/tree/sound/soc/msm/msm-pcm-routing.c?id=4c1e76a598cfdd12b050c2e74644c88f2fbaadab

高通的音频驱动,提供了一个ALSA控制借口

Incall_Music Audio Mixer

用来控制 CPU的 DAI 接口 MultiMedia1 和 MultiMedia2 (对应于 ALSA 设备 pcmC0D0p 和 pcmC0D1p).

可以用下面的命令来给电话的对端播放一个音频文件

tinymix 'Incall_Music Audio Mixer MultiMedia1' 1
tinymix 'Voice Tx Device Mute' 1
tinyplay /sdcard/xiao.wav

测试机器:
红米Note3 全网通 (骁龙650)
红米Note5A (骁龙425)
红米4X (骁龙435)

只是

tinymix 'Voice Tx Device Mute' 1

运行会报  Error: invalid value

参考资料:
https://stackoverflow.com/questions/15204570/inject-uplink-audio-in-call-with-snapdragon-msm8960-soc
https://bbs.pediy.com/thread-223672.htm
https://stackoverflow.com/questions/14432521/background-music-for-call

https://android.googlesource.com/platform/hardware/qcom/audio/+/master/legacy/alsa_sound/AudioHardwareALSA.h

#define INCALLMUSIC_KEY     "incall_music_enabled"

https://android.googlesource.com/platform/hardware/qcom/audio/+/master/hal/voice_extn/voice_extn.h

#ifdef INCALL_MUSIC_ENABLED
int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev,
                                                  struct stream_out *out);
#else
static int voice_extn_check_and_set_incall_music_usecase(struct audio_device *adev __unused,
                                                         struct stream_out *out __unused)
{
    return -ENOSYS;
}
#endif

/dev/snd 下控制文件

.          comprC0D32 hwC0D104 hwC0D125 hwC0D21 hwC0D30   hwC0D40 hwC0D49 pcmC0D0c  pcmC0D13c pcmC0D1c  pcmC0D26c pcmC0D35c pcmC0D41c pcmC0D49p timer 
..         comprC0D43 hwC0D11  hwC0D126 hwC0D24 hwC0D3017 hwC0D41 hwC0D55 pcmC0D0p  pcmC0D13p pcmC0D1p  pcmC0D27c pcmC0D36p pcmC0D41p pcmC0D4p  
comprC0D15 comprC0D44 hwC0D12  hwC0D13  hwC0D25 hwC0D3033 hwC0D42 hwC0D56 pcmC0D10c pcmC0D14c pcmC0D20c pcmC0D27p pcmC0D37c pcmC0D42c pcmC0D5c  
comprC0D16 comprC0D8  hwC0D120 hwC0D14  hwC0D26 hwC0D32   hwC0D43 hwC0D71 pcmC0D10p pcmC0D17c pcmC0D21c pcmC0D2c  pcmC0D38c pcmC0D42p pcmC0D5p  
comprC0D28 controlC0  hwC0D121 hwC0D15  hwC0D27 hwC0D33   hwC0D44 hwC0D72 pcmC0D11c pcmC0D17p pcmC0D22c pcmC0D2p  pcmC0D39p pcmC0D45p pcmC0D6p  
comprC0D29 hwC0D10    hwC0D122 hwC0D16  hwC0D28 hwC0D35   hwC0D45 hwC0D87 pcmC0D11p pcmC0D18p pcmC0D23c pcmC0D33c pcmC0D3c  pcmC0D46p pcmC0D7c  
comprC0D30 hwC0D1000  hwC0D123 hwC0D2   hwC0D29 hwC0D39   hwC0D46 hwC0D88 pcmC0D12c pcmC0D19c pcmC0D24c pcmC0D33p pcmC0D3p  pcmC0D47p pcmC0D9c  
comprC0D31 hwC0D103   hwC0D124 hwC0D20  hwC0D3  hwC0D4    hwC0D48 hwC0D9  pcmC0D12p pcmC0D19p pcmC0D25c pcmC0D34c pcmC0D40c pcmC0D48p pcmC0D9p  

红米6A通话背景音分析


2018-11-18 20:08:51.063 358-1704/? D/AudioALSAPlaybackHandlerVoice: open(), audio_mode: 2, u8BGSUlGain: 0, u8BGSDlGain: 0, audio_format: 3 => 1, sample_rate: 48000 => 32000, ch: 2 => 1, buffer_size: (write)2048, (bgs)5128, flag: 0x6, mLatencyUs: 5333

双4G入网

Dual Sim Dual Volte

目前移动和联通支持情况最为简单,无论移动+移动、移动+联通、联通+联通都没有任何问题,均可支持双4G网络.

Mix2S 中 唯独电信卡相对比较特殊,理论上全网通5.0电信卡作为副卡时可支持VoLTE,但由于现在中国电信的VoLTE服务还未商用,所以目前电信卡作为副卡,暂时只能停留在CDMA 1x,也就是电信2G网络.

红米Note5双电信一样只有设置为上网卡的才能接入网络,无法自动切换,而且移动+电信、联通+电信的组合中,必须把电信卡设置为上网卡才能4G,否则是2G
(支持电信双卡双待,但是不支持电信双4G)

红米6A 对电信卡删除CSIM, 那么双4G数据网也是可以实现的

sim卡商代码

电信
B–江苏恒宝
C–广东楚天龙
D–大唐
G–江西捷德
H–北京华虹
K–上海柯斯 (已经取消)
P–天津金普斯 (同雅斯拓合并为金雅拓,现在属于泰雷兹,代码已经取消)
T–武汉天喻
W–北京握奇
X–珠海东信和平
Y–上海雅斯托 (现在为法国 泰雷兹)

联通
C 上海柯斯  (2015年后已经退出联通供应商序列, 2019年就开始破产清算,到2025年还在扯皮)
N 江苏恒宝
L 东莞楚天龙
D 深圳欧贝特(法国公司,2015年后已经退出联通供应商序列,改名为 爱德觅尔)
E 珠海东信和平
G 天津金普斯 (金雅拓,泰雷兹,代码已经取消)
S 上海雅斯拓 (金雅拓,泰雷兹)
T 大唐微电子
W 北京握奇
H 北京华虹
J 江西捷德(湖北黄石有工厂)
Y 武汉天喻
V 珠海星汉
A 东方英卡(被恒宝收购,代码已经取消)
B 法国布尔(退出联通供应商, 代码已经取消)
M 深圳明华澳汉 (退出联通供应商, 代码已经取消)
Z 航天智通(已取消)
R

移动

0 雅斯拓 (斯伦贝谢/雅思拓/金雅拓/泰雷兹)
1 金普斯 (合并到金雅拓,代码取消)
2 武汉天喻
3 江西捷德
4 珠海东信和平
5 大唐微电子
6 航天九州通 (代码取消)
7 北京握奇
8 东方英卡(恒宝收购)
9 北京华虹
A 上海柯斯
B 航天智通(已取消)

manifeset permission 系统或者签名

在权限检查时,

permission android:name="com.qualcomm.permission.UIM_REMOTE_CLIENT" android:protectionLevel="signatureOrSystem" 

permission android:name="com.qualcomm.permission.UIM_REMOTE_CLIENT" 

是不一样

在apk安装后,权限信息会解析到  /data/system/packages.xml 文件里

...
item name="com.qualcomm.permission.UIM_REMOTE_CLIENT" package="com.qualcomm.uimremoteclient"
...
   package name="com.redteamobile.virtual.softsim"
   perms
      item name="com.qualcomm.permission.UIM_REMOTE_CLIENT" granted="true" flags="0"
   


区别就在于

item name="com.qualcomm.permission.UIM_REMOTE_CLIENT" package="com.qualcomm.uimremoteclient" protection="18"


通过hook系统包管理服务

com/android/server/pm/PackageManagerService.java
android/content/pm/permissionInfo



updatePermissionsLPw


PMS的全局数据结构中


context.checkCallingOrSelfPermission(String permission) 跟踪这个

ContextImpl.checkCallingOrSelfPermission()
checkPermission(String permission, int pid, int uid)


ActivityManagerNative.getDefault().checkPermission(permission, pid, uid);
通过AMS去做检测的

AMS.checkPermission()

ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
ActivityManager.checkComponentPermission


AppGlobals.getPackageManager()
            .checkUidPermission(permission, uid);





PMS.checkUidPermission()

 先调用getUserIdLPr,同PMS的Setting.mUserIds数组中根据uid 查找权限列表。找到则表示有相应的权限,接着再根据传过来的参数坐下判断,看是否有对应的

如没有找到,则去PMS的mSystemPermissions 中找。
这些信息是启动时从 /system/etc/permissions/platform.xml 中读取的



https://android.googlesource.com/platform/frameworks/base.git/+/master/services/core/java/com/android/server/pm/PackageManagerService.java

mPermissionManager.updatePermissions

BasePermission bp = (BasePermission) mPermissionManager.getPermissionTEMP(permName);

mPermissions.put(name, new PermissionData(permissionData)); 修改权限

https://sanjay-f.github.io/2016/05/18/%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E7%B3%BB%E5%88%9736—%E5%AE%89%E5%8D%93%E7%9A%84%E5%AE%89%E5%85%A8%E6%9C%BA%E5%88%B6permission/


在Android 8.0 Oreo后, 权限不会自动赋予那些在 system/priv-app目录的应用。
所有的特权应用,都必须通过 在 /etc/permissions目录下的白名单来配置。
比如 privapp-permissions-platform.xml 里就有
privapp-permissions package=”com.android.phone”

permission name=”android.permission.READ_PRIVILEGED_PHONE_STATE”

的配置

特许权限许可名单
特权应用是位于系统映像某个分区上 priv-app 目录下的系统应用。各 Android 版本中,该分区为:

Android 8.1 及更低版本 – /system
Android 9 及更高版本 – /system, /product, /vendor
在本页面中,/etc/permissions/priv-app 解析为 partition/etc/permissions/priv-app。

过去,设备制造商几乎无法控制可对特权应用授予哪些签名|特许权限。从 Android 8.0 开始,制造商必须在 /etc/permissions 目录下的系统配置 XML 文件中明确授予特许权限。从 Android 9 开始,实现人员必须明确授予或拒绝授予所有特许权限,否则设备将无法启动。

privapp-permissions.xml 文件只有在与特权应用位于同一分区时才能授予或拒绝授予该应用权限。例如,如果 /vendor 分区上的应用请求特许权限,则只能由同样位于 /vendor 上的 privapp-permissions.xml 文件来同意或拒绝该请求。

注意:必须列入许可名单的只有核心平台(“android”软件包)所定义的权限。设备制造商定义的特许权限仍将自动授予。在 privapp-permissions.xml 文件中,请仅列出实际存在于该分区上的应用。如果应用不在该分区上,系统将忽略所列条目。

添加许可名单
应用的权限许可名单可列在位于 frameworks/base/etc/permissions 目录下的单个或多个 XML 文件中,如下所示:

/etc/permissions/privapp-permissions-OEM_NAME.xml
/etc/permissions/privapp-permissions-DEVICE_NAME.xml
对于如何组织内容,没有严格的规则。设备实现人员可以决定内容结构,只要 /system/priv-app 下的所有应用均列入许可名单即可。例如,Google 针对由 Google 开发的所有特权应用提供了一个许可名单,并建议使用以下组织方式:

对于已包含在 Android 开源项目 (AOSP) 树中的应用,请将其权限列在 /etc/permissions/privapp-permissions-platform.xml 中。
对于 Google 应用,请将其权限列在 /etc/permissions/privapp-permissions-google.xml 中。
对于其他应用,请使用以下格式的文件:/etc/permissions/privapp-permissions-DEVICE_NAME.xml。

智能卡安全机制比较CardOS

作者: smarticcard (微信号)

自从智能卡开始进入人们的日常生活之后,大家对于智能卡的安全性普遍看好,但是不同公司的智能卡在安全机制的实现方面也存在很多的差异。对于智能卡应用开发和智能卡COS设计人员来说,如果能够更多地了解不同公司的智能卡安全机制,无疑会对自己的开发过程有所帮助。在此将逐步介绍一些流行的智能卡操作系统中各具特色的安全机制,究竟这些安全机制孰优孰劣,其实无关紧要,只要这种安全机制能够满足系统的安全需求就足够了。

首先看看早期的CardOS,CardOS是西门子公司基于自己的44C40/80系列芯片而设计的,该系列芯片RAM大小256字节,程序空间8K/16K,数据空间4K/8K,采用西门子的8051内核。CardOS在1995年推出了1.2版本,主要的APDU命令是符合ISO7816-4的文件读写操作,采用的安全机制非常灵活,初看起来也有点复杂,但是实际原理却是比较简单的。虽然目前国内市场上几乎已经没有什么CardOS产品了,但是了解这个初期的鼻祖级的智能卡安全机制,对于了解目前市场上流行的COS安全机制应该会有些帮助。

CardOS采用半字节作为安全状态,除却0和F之外,还有1到E共计14种状态,每个状态分别对应要达到该状态需要进行的某种安全认证操作以及这些认证的不同组合方式,这些安全认证包括校验PIN或者是C/R (Challenge / Response) 认证(也就是我们现在通常所说的外部认证),而认证的组合方式包括“逻辑与”及“逻辑或”。

对于文件的操作和密钥的使用可以定义不同的安全状态,只有满足定义的安全状态后才能进行相应的文件操作,或者密钥的使用。无论是DF还是EF都有一组3字节的安全状态控制字,每半字节作为一种访问控制的状态标识,分别对应着文件的建立、删除、添加、读取、更新等操作。

这些安全状态及其需要的认证或组合全部保存在一个特殊的内部文件STCF(Security Test Control File)安全认证控制文件中,该文件是一个TLV(Tag Length Value)结构的记录文件,其中第一个字节就是1-E这14个状态中的一个作为TAG,Length根据认证方式的不同而存在差别,Value当中的第一个字节表示认证类型,从中可以看出这个认证是需要PIN认证,还是需要C/R认证,或者是某几个认证状态的“逻辑与”及“逻辑或”组合。对于PIN认证还可以指出应该使用哪个PIN文件中的哪个PIN,同样对于C/R认证也可以指出应该使用哪个密钥文件中的哪个密钥。在CardOS的系统中有一个安全状态bit mask标志,用不同的数据位来记录哪个安全状态经过认证得到了满足。在有些情况下,进行DF选择之后,当前DF的认证状态的bit mask标志将会被清空。

关于“逻辑与”和“逻辑或”其实也很简单。比如“03”的状态表示认证第3个PIN文件中的第2个PIN,“0B”的状态表示需要对第1个密钥文件的第5条密钥进行C/R认证。那么我们可以定义状态“06”表示“03”和“0B”的逻辑或组合,定义状态“07”表示“03”和“0B”的逻辑与组合。我们假设有两个文件EF01和EF02,其中EF01读写的安全状态分别为“03”和“06”,EF02读写的安全状态分别为“0B”和“07”。那么在验证了第3个PIN文件中的第2个PIN后,即可以读EF01也可以写EF01,而对于第一个密钥文件的第5条密钥经过C/R认证后,也可以写EF01。对于EF02的写操作必须同时满足以上两个认证状态,对于EF02的读则只需要C/R认证第1个密钥文件的第5条密钥即可。

除了以上的安全状态控制机制之外,CardOS还定义了所谓的线路保护LINE PROTECTION,在文件的创建过程中会定义LPROTF字段,作为线路保护属性,有两种线路保护模式分别为MAC方式和加密方式,同时还定义了线路保护的方向,即从卡到终端以及从终端到卡。而用来进行线路保护的密钥只能存储在SKF(System Key File)系统密钥文件中。

在CardOS中定义了几个默认的EF文件标识,分别为:0000 = ATR二进制文件,0001 = STCF记录文件,0002 = PIN记录文件,0003 = SKF系统密钥记录文件,0004 = RSF 随机数种子二进制文件。CardOS支持最多6层DF文件结构,可以通过文件名、文件标识、文件路径等方式进行文件的选择。