【问题标题】:error generating signed CSR with javacard (asn1 bad tag value)使用 javacard 生成签名 CSR 时出错(asn1 错误标记值)
【发布时间】:2017-03-05 13:18:34
【问题描述】:

我已在 java 卡中生成密钥对并返回公钥。我在 android 应用程序中再次生成公钥,然后在 android 中生成 CSR

 private byte[] CertReqGeneration()  throws Exception
 {
    if(publickeyobj==null)
        return null;

    String info = "CN=cn, OU=ou, O=o, C=cn, ST=city";
    X500Principal x500 = new X500Principal(info);

    X500Name x500name;
    x500name= X500Name.getInstance(x500.getEncoded());

    CertificationRequestInfo csrInfo = new CertificationRequestInfo(x500name, publickeyobj, new DERSet());

    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(csrInfo);
    ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier("0.0");
    v.add(new DERSequence(oid));
    v.add(new DERBitString(new byte[] {}));
    byte[] encoded = new DERSequence(v).getEncoded();
    byte[] PKCS10= DataSignGeneration(encoded);

       byte[] encoded = Base64.encode(PKCS10);
      String base64=new String(encoded);
    return  base64;

}

但是当我想在 ca 中发出它时,我收到错误 asn1 bad tag value met 0x8009310b

这是我的登录小程序代码:

  //sign
      Signature signature=Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1,false);
      signature.init(thePrivateKey,Signature.MODE_SIGN);
      signLength=signature.sign(buffer,(short)(ISO7816.OFFSET_CDATA & 0xFF), inputlength, buffer, (short)(0));

这是我的代码生成的签名 csr

G1Xsg/fetpr1/RfbUzWmDqRqu2GvymoQwXUJS/tB36l1SAvrRyDtwCgVHB3ukYFSZJeavFISQ9+R4zD1qxjO6r/E2/3o9UfARm2GeTwEZFv8LVgULAPc/e64v5xkiQYO05QwHa5PtmaXXD4NtuSNvF9xgNjtdAkosKqEPLcme5k=

【问题讨论】:

  • 谢谢亚伯拉罕先生。我应该查看 pkcs#10 格式吗?
  • 感谢亲爱的 pedrofb 编辑我的问题

标签: android bouncycastle javacard csr


【解决方案1】:

此错误似乎意味着私钥(在发出证书请求时创建)与公钥(.crt 文件)不匹配。密钥对未成功加入有效的 SSL 证书。

解决方案: 首先将 .crt 文件导入本地计算机的个人证书存储区。 (开始按钮>运行:MMC>文件菜单>添加/删除管理单元>突出显示证书管理单元并单击添加按钮>选择计算机帐户并单击完成>单击确定>钻入个人>证书>右键单击并选择所有任务 > 选择导入 > .crt 文件指南。)此时您的证书基本上是半证书。它仍然缺少它的私钥。

其次,双击刚刚导入的crt证书文件,选择Details选项卡,一直向下滚动到Thumbprint并突出显示Thumbprint。在下部窗格中,阻止并复制指纹的所有字母。将指纹字符粘​​贴到记事本中。打开命令提示符并运行以下命令:Certutil /?

您要运行的命令是:

certutil -repairstore my “{在此处插入所有指纹字符}”

当您看到响应:“CertUtil:-repairstore 命令已成功完成”时,您应该有一个与个人存储中的 .crt 文件关联的私钥。不再需要运行“完成证书请求...”向导。此时证书应显示在 IIS 管理器的服务器证书列表中。尝试编辑网站的 https 绑定时,它也应该在 SSL 证书下拉列表中可用。

参考:https://blogs.msdn.microsoft.com/webtopics/2009/01/03/asn1-bad-tag-value-met-error-when-processing-a-certificate-request-in-iis-7/

【讨论】:

  • 感谢您的回复。我在 java 卡上生成了密钥对..为什么是 ssl?我认为产生了不良的csr。但我在这里写了我的代码。我不知道在生成的密钥对中哪里出错了?
  • 好的,但是尝试关联公钥和私钥,以便密钥对成功连接在一起。当生成的密钥对之间没有任何关联时,就会出现错误的标签值错误。
  • 非常感谢。但我想在卡片中生成,这项工作是自动流动的。
【解决方案2】:

让我们先看看您生成的 CSR。我用an online ASN.1 decoder

嗯,在线工具不会解码您的 CSR。所以它是无效的:

好的,让我们看看有效的 CSR 是什么样的。我使用 OpenSSL 生成了 CSR:

ghasemi@ghasemi-MS-7693:~$ openssl genrsa -out priv.key 1024
Generating RSA private key, 1024 bit long modulus
............................++++++
.......................++++++
e is 65537 (0x10001)
ghasemi@ghasemi-MS-7693:~$ ls
priv.key
ghasemi@ghasemi-MS-7693:~$ openssl req -new -key priv.key -out my_csr.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:IR 
State or Province Name (full name) [Some-State]:Tehran
Locality Name (eg, city) []:Tehran
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Company
Organizational Unit Name (eg, section) []:Section
Common Name (e.g. server FQDN or YOUR name) []:Ebrahim
Email Address []:ebr.ghasemi at gmail 

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

ghasemi@ghasemi-MS-7693:~$ ls
my_csr.csr  priv.key

如您在上面看到的,我生成了一个带有 1024 位密钥对的 CSR。让我们看看内容:

ghasemi@ghasemi-MS-7693:~$ cat my_csr.csr 
-----BEGIN CERTIFICATE REQUEST-----
MIIByzCCATQCAQAwgYoxCzAJBgNVBAYTAklSMQ8wDQYDVQQIDAZUZWhyYW4xDzAN
BgNVBAcMBlRlaHJhbjEQMA4GA1UECgwHQ29tcGFueTEQMA4GA1UECwwHU2VjdGlv
bjEQMA4GA1UEAwwHRWJyYWhpbTEjMCEGCSqGSIb3DQEJARYUZWJyLmdoYXNlbWkg
YXQgZ21haWwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJK2YUOSREjrDbZ
auC3/509NOAL+xjqJ2x947CtSIyuPSLuplDW4oAkvaqYvA5ocIxeAGbW9WZF/OdM
8z5XoQF3+ogGsEna1TZN1TY5XOdrRgIu9gFA2KRNPjnEZIkt7FLBJUQlk5aithk4
lfy73XCoosjWUwBOKac5ZIKOuXEHAgMBAAGgADANBgkqhkiG9w0BAQsFAAOBgQCF
hQzkAgfongzP9EKV+oTwVhqkQ7bfy5TE85YIR3aymuzbvAc9KWdWydOxHiHqXbmZ
ECWvLlMsrlrpyDO2Xxy8UXFJkNgH4Rys267ETaoYh19htc4qZzNqK/1ejQBUidgY
QoafJxv3YhO+gYr2txyxPRN0etcquElwx0odF8KBVA==
-----END CERTIFICATE REQUEST-----
ghasemi@ghasemi-MS-7693:~$ 

嗯,明显不同的是长度以及开始和结束线。我的CSR真的比你大。它以-----BEGIN CERTIFICATE REQUEST----- 开头,也以-----END CERTIFICATE REQUEST----- 结尾。

让我们用 ASN.1 解码器检查它的内容:

好的。如您所见,我在 CSR 生成期间以纯文本形式输入了 CSR 中的字符,但在您的中没有。

那怎么了?

您的小程序,仅返回您的 CSR 信息的 签名。它不是企业社会责任,它只是它的签名。因此,您必须使用 CSR 信息Signature 生成 CSR。此外,CSR 信息中使用的公钥必须是其私钥用于生成签名的公钥,否则 CA 将无法验证 CSR 的有效性,并将您的 CSR 视为伪造/伪造的 csr .

因此,在卡内生成 KeyPair 后,将公钥导出到 android 应用程序。然后生成 CSR 信息并在卡内生成此信息的签名,然后使用 csr 信息和签名构建您的 CSR。

【讨论】:

  • 谢谢。正如您在我的代码中看到的,我按照您所说的做了所有事情。我从卡中获取了公钥并在 android 中重新生成了公钥。我想我应该在 asn1 中添加 csr + csr 的签名(两者)。对吗?
【解决方案3】:

@Abraham 分析似乎正确:生成的 CSR 内容无效

我猜这段代码的目的是构建 ASN.1 结构以进行签名,但 bouncycastle 会为您完成。

ASN1EncodableVector v = new ASN1EncodableVector();
v.add(csrInfo);
ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier("0.0");
v.add(new DERSequence(oid));
v.add(new DERBitString(new byte[] {}));
byte[] encoded = new DERSequence(v).getEncoded();
byte[] PKCS10= DataSignGeneration(encoded);

在 cmets 之后我们可以看到需要创建一个未签名的 PKCS10 请求发送到 javacard 进行签名,并获取结果来构建签名的 PKCS10 请求

Bouncycastle 不提供执行该操作的 API。我建议查看PKCS10 示例和PKCS10CertificateRequestBuilder 的源代码以适应使用您的Java 卡。如果你想在 android 中使用,你需要特殊的发行版 spongycastle。

这是一个创建未签名请求的工作示例(没有 java 卡,但应该很容易适应。只是签名过程)

public byte[] generateCSR (X500Name subject, PublicKey publicKey, String signatureAlgorithm) throws Exception{
    //Create the unsigned CSR
    CertificationRequestInfo info = new CertificationRequestInfo(
                    x500name, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()),new DERSet());

    //The CSR bytes to be signed
    byte dataToSign[] = info.getEncoded(ASN1Encoding.DER);

    //Send the CSR to the card
    byte signedData[] = signOnJavaCard (dataToSign,signatureAlgorithm);

    //Build the signed CSR
    AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm);
    PKCS10CertificationRequest csr = new PKCS10CertificationRequest(
                    new CertificationRequest(info, sigAlgId, new DERBitString(signedData)));
    byte signedCSR = csr.getEncoded();

    //Verify signature validity
    ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(new BouncyCastleProvider()).build(publicKey);
    boolean valid = csr.isSignatureValid(verifier);

    return signedCSR;
}

为了测试我使用了本地签名方法的代码

public byte signOnJavaCard (byte dataToSign[], String signatureAlgorithm)
    Signature signature = Signature.getInstance(signatureAlgorithm);
    signature.initSign(privateKey); //get the private key in some way...
    signature.update(dataToSign);
    return signature.sign();
}

【讨论】:

  • 当你想向Javacard发送一些数据(在这个例子中是要签名的数据),你需要把它们放在一个叫做APDU命令的结构中。 APDU 命令由一个固定的 5 字节头 + 一个可选的数据体组成。问题中的 5 索引是因为固定的标题。
  • 由于 Javacard 硬件的硬件限制,它们不支持很多 Java 库和功能。例如,它们通常不支持 int 类型。 javacards没有充气城堡库。
  • 好的,@Abraham,了解 OFFSET_CDATA。 Bouncycastle在Android代码中使用,只需要通过Bouncycastle api向卡片发送签名操作
  • 非常感谢。但我需要未签名的 pkcs#10 请求,因为我应该使用 java 卡中的私钥对其进行签名。我使用此代码。对不对?blog.pastelstudios.com/2015/04/21/…
  • 我不知道它是否正确但它不完整。它没有解释必须签署哪些数据以及如何构建签署的 CSR 请求。最好的选择是查看 bouncycastle 源代码。你用的是什么版本?
猜你喜欢
  • 2013-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
  • 2016-01-03
  • 2021-08-03
相关资源
最近更新 更多