繁体   English   中英

修改X509证书

[英]Modifying X509 certificate

我想表明,如果我从给定的 X509 证书中修改一个位或一个字节,则签名验证结果为假(因为此修改导致与证书不同的哈希值)。 我陷入了如何使用getTBSCertificate()方法对证书进行修改的情况。 我的以下代码完美地完成了验证过程,但我试图使用位或字节修改的想法使其失败,但它不起作用。 请注意,我提出的这个想法是为了证明对证书的任何修改都会导致签名验证失败

public class VerifyX509 {

private static Certificate getCACert;
private static Certificate[] getCert;

public static void main(String[] args) throws CertificateEncodingException {
    setURLConnection("https://www.google.com");
    X509Certificate x509cert= (X509Certificate) getCert[0];
    byte[] b= x509cert.getTBSCertificate();
    b[0] = (byte) ~b[0];
    // HOW TO UPDATE getTBSCertificate() after flipping the b[0] to make Verify() in my method verifySign() return false!
    verifySign();

  }


public static void setURLConnection(String link){

    try{
        int i=1;
        URL destinationURL = new URL(link);
        HttpsURLConnection con = (HttpsURLConnection) destinationURL.openConnection();
        con.connect();
        getCert = con.getServerCertificates();
        for (Certificate c : getCert) 
        {
            if (i==2)
            {
                getCACert= c;
                return;
            }
            i+=1;
        }
        }catch (Exception e1) {
        JOptionPane.showMessageDialog(null, "Error while connection! Check your Internet Connection.");
        e1.printStackTrace();
        }

}


public static boolean verifySign()
{

        try
        {
            getCert[0].verify(getCACert.getPublicKey());
            return true;
        } catch (GeneralSecurityException e2)
        {
            return false;
        }
}
}

如何设置概念验证代码以显示验证失败?

请注意,我提出的这个想法是为了证明对证书的任何修改都会导致签名验证失败。

可以通过简单地翻转有效证书中的随机位然后尝试验证它们来证明这一点(以一定的正确概率)。

但是,您无法证明这样的事情。 正确的证明需要:

  1. 正确实施 X509 证书的数学证明具有更改证书会使其无效的属性(某些概率非常接近1 )。

  2. 正式方法证明加载证书和进行验证的代码已正确实现。


1 - 事实上,很容易看出概率不能完全为 1。 应用鸽笼原理。

byte[] b= x509cert.getTBSCertificate();
b[0] = (byte) ~b[0];

更改从证书获得的数组中的字节不会更改证书。

您必须使用CertificateFactory.从字节数组中重新加载它CertificateFactory.

迈克先生,你要做的就是获取行数据DER编码的证书信息(TBS部分),你可以像下面这样提取它

URL url = new URL("https://www.google.com/");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.connect();
Certificate userCert[] = con.getServerCertificates();
        X509Certificate x509cert = ((X509Certificate) userCert[0]);


        byte[] tbs=x509cert.getTBSCertificate(); 

然后通过循环将数组 b 的内容复制到另一个数组 bcopy 并执行您想要的任何修改(即使用屏蔽技术 Anding with x55),然后您可以通过

    String sha1 = "";
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(bcopy);
        sha1 = byteToHex(crypt.digest());

private static String byteToHex(final byte[] hash)
{
    Formatter formatter = new Formatter();
    for (byte b : hash)
    {
        formatter.format("%02x", b);
    }
    String result = formatter.toString();
    formatter.close();
    return result;
}

此时你有了修改后的证书的哈希值,你现在可以去从原始证书中提取签名[ byte[] sig= x509cert.getSignature(); ] 并解密签名以获取哈希值并将其与修改后的哈希值进行比较,祝你好运;)

如果您查看 RFC 5280,证书有 3 个字段:

  • tbs证书
  • 签名算法
  • 签名值

签名值是证书中的最后一项。

我也有类似的需求。 这些是我遵循的步骤:

  • 拥有 1 个 .crt 格式(base-64 编码)文件的证书。 证书包含在“-----BEGIN CERTIFICATE-----”和“-----END CERTIFICATE-----”之间
  • 在 END CERTIFICATE 行之前的行中编辑证书的最后一个字符。 只需在该字符上加 1 或减少 1。如果最后一个字符是 x,则将其设为 y 或 w。

这将更改证书中的签名,签名将不再有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM