新的主题哈希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.c
和x509_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相同。