从 PIV 智能卡中提取名称

Extract names from PIV smartcard

我正在尝试从 PIV 智能卡中提取以下内容:

  1. 主题通用名称
  2. 证书使用者替代名称/Microsoft 主体名称

我正在使用 RedHat 6(最终是 7)和 CoolKey 作为我的 PKCS11 模块。

我需要一种无需智能卡 pin 即可通过代码提取此信息的方法,无论是来自 shell 命令还是智能卡库。目前,我可以通过使用 shell 命令 'pkcs11-tools --module -T' 来获取通用名称,因此主题替代名称确实是我所追求的,但我想找到一种更好的方法来获取通用名称(如果可用)。

我知道无需输入 PIN 码即可获得此信息,因为我可以在 RHEL (esc) 上包含的智能卡管理器中查看所有信息。如果重要的话,我有根证书链、中间证书链和从属证书链。

我的想法是我必须从卡中提取证书,用我的本地 CA 验证该证书,然后解密它。我花了几天时间阅读有关 APDU、智能卡和 openssl 的文档,但一无所获。

编辑 RHEL智能卡管理器视图:

这是智能卡查看器在您打开卡片并查看详细信息时显示的内容。 Microsoft Principal Name 是我要从卡片中提取的名称,以及显示在层次结构部分和其他位置的“通用名称”,以红色文本显示。

我实际上已经切换到使用 pkcs15-tool,因为 pkcs11-tool 切断了更长的通用名称(您可以在屏幕截图的标题栏中看到这一点,同一个问题)。 输出:'pkcs15-tool --list-info'

Using reader with a card: <reader name>
PKCS#15 Card [LASTNAME.FIRSTNAME.MIDDLENAME.12345678]:
        Version          : 0
        Serial number    : <big string>
        Manufacturer ID  : piv_II
        Flags            :

我目前的方法是简单地将括号中的字符串解析为通用名称,然后让用户使用 Redhat smartcard 工具手动输入 Alt Name。

我能够通过使用 Java bouncycastle 和 iaik pkcs11 包装器获得通用名称和 UPN/Certificate 替代名称。

//path to .so library file
Module pkcs11Module = Module.getInstance(this.getProperties().getProperty("PKCS11_LIBRARY"));
pkcs11Module.initialize(null);
Slot[] slotsWithToken = pkcs11Module.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
for(Slot s : slotsWithToken)    {
    Session session = s.getToken().openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RO_SESSION, null, null);
    session.findObjectsInit(new X509PublicKeyCertificate());
    Object[] objects = null;
    while((objects = session.findObjects(1)).length > 0)    {
        for(Object c : objects) {
            X509PublicKeyCertificate cert = (X509PublicKeyCertificate) c;
            byte[] certValue = cert.getValue().getByteArrayValue();
            Certificate cc = certFactory.generateCertificate(new ByteArrayInputStream(certValue));
            if(cc instanceof X509Certificate)   {
                X509Certificate x509 = (X509Certificate) cc;
                //COMMON NAME:
                String name = new X500Name(x509.getSubjectDN().getName()).getRDNs()[0].getFirst().getValue().toString();
                Collection<List<?>> altNames = x509.getSubjectAlternativeNames();
                for(List<?> list : altNames)    {
                    ASN1Sequence seq = ASN1Sequence.getInstance(new ASN1InputStream(new ByteArrayInputStream((byte[]) list.get(1))).readObject());
                    ASN1TaggedObject obj = (ASN1TaggedObject) seq.getObjectAt(1);
                    //ALT NAME:
                    String upn = obj.getObject().toString();
                    upn = upn.substring(upn.lastIndexOf("]") + 1);
                }
            }
        }
    }
}

upn 前面附加了“[0]”,我不确定这是为什么,所以我对其进行操作以消除它。