新的主题哈希openssl算法不同

从Java Framework管理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);之前或之后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. * */ 

你离它不是很远,如果你想要与OpenSSL新的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新的Subject_hash相同。