【问题标题】:The new subject hash openssl algorithm differs新的主题哈希 openssl 算法不同
【发布时间】:2013-10-14 18:06:00
【问题描述】:

我在从 Java 框架管理 openssl 证书时遇到了问题。

openssl x509 -subject_hash ...

输出与 Java 框架在调用 X509_NAME_hash() 时返回的不同,见下文。

原因是 openssl 改变了它计算 SHA1 的方式。现在,它不像 MD5 那样基于主题的 ASN.1 DER 表示中的散列,而是首先计算 CANONICAL 表示,然后在此基础上计算 ASN.1 DER,然后将其用作SHA1 算法的输入。

NativeCrypto.java

// --- X509_NAME -----------------------------------------------------------
public static int X509_NAME_hash(X500Principal principal) {
    return X509_NAME_hash(principal, "SHA1");
}

private static int X509_NAME_hash(X500Principal principal, String algorithm) {
    try {
        byte[] digest = MessageDigest.getInstance(algorithm).digest(principal.getEncoded());
        return Memory.peekInt(digest, 0, ByteOrder.LITTLE_ENDIAN);
    } catch (NoSuchAlgorithmException e) {
        throw new AssertionError(e);
    }
}

我正在从 openssl 库中查看 x_name.cx509_cmp.c 以尝试在 Java 底层中修复它。但我没有成功。

我知道我必须修改x509_cmp.c 中的X509_NAME_hash 方法。但不确定该更改应该在i2d_X509_NAME(x,NULL); 之前还是之后 此方法正在计算主题名称的 CANONICAL 表示,对吗?那么,我需要根据该输出计算 ASN1 DER,对吗?但我就是做不到。

如果有人能指导我或通过一些线索来解决这个问题,我将不胜感激。

x509_cmp.c

    unsigned long X509_NAME_hash(X509_NAME *x)
    {
    unsigned long ret=0;
    unsigned char md[SHA_DIGEST_LENGTH];

    /* Make sure X509_NAME structure contains valid cached encoding */
    i2d_X509_NAME(x,NULL);
    if (!EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(),
            NULL))
            return 0;

    ret=(   ((unsigned long)md[0]     )|((unsigned long)md[1]<<8L)|
            ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L)
            )&0xffffffffL;
    return(ret);
    }

函数x509_name_canon 显然执行了重新编码。这是crypto/asn1/x_name.c:

/* This function generates the canonical encoding of the Name structure.
 * In it all strings are converted to UTF8, leading, trailing and
 * multiple spaces collapsed, converted to lower case and the leading
 * SEQUENCE header removed.
 * 
 */

【问题讨论】:

标签: java algorithm openssl sha1 x509


【解决方案1】:

您离它不是很远,如果您想要与 OpenSSL new SubjectHash 相同的结果,您必须删除 DN 的前导序列。因此你必须做这样的事情:

// --- X509_NAME -----------------------------------------------------------

public static int X509_NAME_hash(X500Principal principal) {
    return X509_NAME_hash(principal, "SHA1");
}

private static int X509_NAME_hash(X500Principal principal, String algorithm) {
    try {

        byte[] princ = principal.getEncoded();
        final ASN1Sequence obj = (ASN1Sequence) ASN1Object.fromByteArray( princ );

        // Remove the leading sequence ...
        final DERSet enc = (DERSet) obj.getObjectAt(0);
        final byte[] toHash = enc.getDEREncoded();

        MessageDigest md = MessageDigest.getInstance(algorithm);
        byte[] digest = md.digest(toHash);
        return Memory.peekInt(digest, 0, ByteOrder.LITTLE_ENDIAN);

    } catch (NoSuchAlgorithmException e) {
        throw new AssertionError(e);
    } catch (IOException e) {
        throw new AssertionError(e);
    }
}

结果与 OpenSSL new Subject_hash 相同。

【讨论】:

  • 我很困惑这是如何工作的。您获得了第一个集合,但该序列包含多个集合。从princ[] 你需要跳过前(三个)字节的标签和长度吗?
猜你喜欢
  • 1970-01-01
  • 2016-06-23
  • 1970-01-01
  • 1970-01-01
  • 2020-03-26
  • 2016-12-15
  • 2014-05-01
  • 2012-05-24
  • 1970-01-01
相关资源
最近更新 更多