我一直在爲此奮鬥了幾天。我正在研究在嵌入式Linux環境中運行的Java 1.7應用程序。 OpenSSL不可用,我無法控制設備上操作系統映像中的內容。我需要計算自簽名X.509證書的主題散列,產生與OpenSSL 1.0+相同的結果。這個現有的回答讓我開始:Java 1.7主題Hash of X.509證書OpenSSL 1.0+兼容
The new subject hash openssl algorithm differs
從我的測試應用程序的代碼如下所示。我的計算適用於主題名稱僅包含CN值的證書,但對於指定了任何其他主題組件(OU,O,L,ST或C)的證書不起作用。對於那些證書,整個主題上的散列(不包括前奏序列)不匹配。根據上面的答案,我已經提取了每個組件(使用getObjectAt()方法),並單獨對每個組件進行散列處理(沒有快樂),顛倒了它們的順序並且散列了它們(沒有喜悅),以及其他一些變體主題。我一直在努力避免我擔心的是下載OpenSSL源代碼並使其運行更耗時,因此我可以檢查中間結果並查看出錯的地方。也許有人這樣做可以提供一些指導。
private static void getSubjectHash(X509Certificate x509Cert)
{
try {
// get the subject principal
X500Principal x500Princ = x509Cert.getSubjectX500Principal();
// create a new principal using canonical name (order, spacing, etc.) and get it in ANS1 DER format
byte[] newPrincEnc = new X500Principal(x500Princ.getName(X500Principal.CANONICAL)).getEncoded();
// read it in as an ASN1 Sequence to avoid custom parsing
ASN1InputStream aIn = new ASN1InputStream(newPrincEnc);
ASN1Sequence seq = (ASN1Sequence) aIn.readObject();
List<byte[]> terms = new ArrayList<>();
int finalLen = 0;
int i = 0;
// hash the encodables for each term individually and accumulate them in a list
for (ASN1Encodable asn1Set : seq.toArray()) {
byte[] term = ((ASN1Set) asn1Set).getEncoded();
terms.add(term);
finalLen += term.length;
// digest the term
byte[] hashBytes = truncatedHash(getDigest(term), 4);
printByteArray(String.format("hash of object at %d:", i++), hashBytes);
System.out.println("");
}
// hash all terms together in order of appearance
int j = 0;
byte[] finalEncForw = new byte[finalLen];
for (byte[] term : terms)
for (byte b : term)
finalEncForw[j++] = b;
// digest and truncate
byte[] hashBytes = truncatedHash(getDigest(finalEncForw), 4);
printByteArray("hash of all terms in forward order", hashBytes);
System.out.println("");
// hash all terms together in reverse order
j = 0;
byte[] finalEncRev = new byte[finalLen];
for (int k = terms.size() - 1; k >= 0; --k)
for (byte b : terms.get(k))
finalEncRev[j++] = b;
// digest and truncate
hashBytes = truncatedHash(getDigest(finalEncRev), 4);
printByteArray("hash of all terms in reverse order", hashBytes);
}
catch (Exception ex) {
throw new RuntimeException("uh-oh");
}
}
private static byte[] getDigest(byte[] toHash)
{
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA1");
}
catch (NoSuchAlgorithmException nsa) {
throw new RuntimeException("no such algorithm");
}
return md.digest(toHash);
}
private static byte[] truncatedHash(byte[] hash, int truncatedLength)
{
if (truncatedLength < 1 || hash.length < 1)
return new byte[0];
byte[] result = new byte[truncatedLength];
for (int i = 0; i < truncatedLength; ++i)
result[truncatedLength - 1 - i] = hash[i];
return result;
}
private static void printByteArray(String name, byte[] bytes)
{
System.out.println(name + " length=" + String.valueOf(bytes.length));
for (byte b: bytes) {
System.out.print(String.format("%02X ", Byte.toUnsignedInt(b)));
}
System.out.println();
}
構建OpenSSL。我的openssl和DER編碼的數據略有不同。看來,openssl將每個主題名稱條目標記爲0x0C而不是0x13(可打印的字符串)。儘管如此,0x0C並沒有出現在X.208允許標籤的表格中,所以我不確定這是什麼意思。我使用上面的標籤CN作爲0x0C,但所有其他主題名稱條目爲0x13的ASN1庫。這就是爲什麼當CN以外的項目存在時,我不匹配openssl的原因。我可以用膠帶粘貼,但我想明白爲什麼。規格更新的MOD? – NefariousB