我有一个 Node 项目(用 TypeScript 编写),我想添加一个函数来获取 PEM 证书的主题哈希值,我需要它以与 OpenSSL 相同的方式计算哈希值,但不使用 OpenSSL(b/c 我的代码需要在可能未安装 OpenSSL 的各种平台上运行)。
所以假设我有一个名为
my-cert.pem
的文件。当我运行 openssl x509 -inform PEM -subject_hash_old -in my-cert.pem | head -1
时,它输出 2889162b
然后我尝试了以下在 TypeScript 中计算哈希值的方法,看看是否可以获得相同的值:
import crypto from 'node:crypto';
import forge from 'node-forge';
public static getSubjectHashFromPEM1(pemCertificate: string): string {
const cert = new crypto.X509Certificate(pemCertificate);
const subject = cert.subject.replaceAll('\n', ', ');
const hash = crypto.createHash('sha1').update(subject).digest('hex').slice(0, 8);
return hash;
}
public static getSubjectHashFromPEM2(pemCertificate: string): string {
const cert = forge.pki.certificateFromPem(pemCertificate);
const subject = cert.subject;
const subjectString = subject.attributes.map(attr => `${attr.shortName ?? ''}=${attr.value as string}`).join(', ');
const hash = crypto.createHash('sha1').update(subjectString).digest('hex').slice(0, 8);
return hash;
}
但是这两个方法都返回
d89c7493
,这与 OpenSSL 返回的 2889162b
不同。
我在这里做错了什么?
我设法让它工作如下:
private static getSubjectHashOld(cert: forge.pki.Certificate): string {
// 1. Extract the subject name in ASN.1 format
const subjectAsn1 = forge.pki.distinguishedNameToAsn1(cert.subject);
// 2. Convert the subject to DER-encoded form
const derSubject = forge.asn1.toDer(subjectAsn1).getBytes();
// 3. Create an MD5 hash of the DER-encoded subject
const md = forge.md.md5.create();
md.update(derSubject, 'raw');
const md5Hash = md.digest().getBytes();
// 4. The first four bytes of the MD5 hash are the subject hash in little-endian format
const hashBuffer = forge.util.createBuffer(md5Hash.slice(0, 4), 'raw');
const hashArray = Array.from(hashBuffer.bytes()).reverse();
// 5. Convert the little-endian hash to a hexadecimal string
const subjectHash = hashArray.map(byte => ('00' + byte.charCodeAt(0).toString(16)).slice(-2)).join('');
return subjectHash;
}