Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/util/certificates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,9 @@ class CA {
}
}
const subjectDistinguishedName = new x509.Name(subjectJsonNameParams).toString();
const issuerDistinguishedName = this.caCert.subject;
// Preserve the encoded name: text conversion can change ASN.1 string types,
// preventing clients that compare issuer/subject DER from building the chain.
const issuerDistinguishedName = this.caCert.subjectName;

const notBefore = new Date();
notBefore.setDate(notBefore.getDate() - 1); // Valid from 24 hours ago
Expand Down
57 changes: 57 additions & 0 deletions test/certificate-issuer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Buffer } from 'buffer';
import * as x509 from '@peculiar/x509';
import { AsnConvert } from '@peculiar/asn1-schema';
import { Certificate } from '@peculiar/asn1-x509';

import { getCA } from '../src/util/certificates';
import { expect, nodeOnly } from './test-utils';

nodeOnly(() => {
describe("External CA issuer encoding", () => {
for (const certificateTransparency of [false, true]) {
it(`preserves the encoded CA name with CT ${certificateTransparency ? 'enabled' : 'disabled'}`, async () => {
const keys = await crypto.subtle.generateKey(
{ name: 'ECDSA', namedCurve: 'P-256' },
true,
['sign', 'verify']
);

// ASCII text can legitimately use UTF8String, as OpenSSL-generated
// names do. Converting this name to text loses that distinction.
const name = new x509.Name([
{ C: [{ printableString: 'GB' }] },
{ O: [{ utf8String: 'Example Organization' }] },
{ CN: [{ utf8String: 'Example Test CA' }] }
]);
const root = await x509.X509CertificateGenerator.createSelfSigned({
name,
serialNumber: '01',
notBefore: new Date(Date.now() - 60_000),
notAfter: new Date(Date.now() + 86_400_000),
signingAlgorithm: { name: 'ECDSA', hash: 'SHA-256' },
keys,
extensions: [
new x509.BasicConstraintsExtension(true, undefined, true),
new x509.KeyUsagesExtension(x509.KeyUsageFlags.keyCertSign, true)
]
});
const key = x509.PemConverter.encode(
await crypto.subtle.exportKey('pkcs8', keys.privateKey),
'PRIVATE KEY'
);

const ca = await getCA({ key, cert: root.toString('pem'), certificateTransparency });
const leaf = new x509.X509Certificate((await ca.generateCertificate('localhost')).cert);
const rootAsn = AsnConvert.parse(root.rawData, Certificate);
const leafAsn = AsnConvert.parse(leaf.rawData, Certificate);

expect(leaf.issuer).to.equal(root.subject);
expect(Buffer.from(AsnConvert.serialize(leafAsn.tbsCertificate.issuer)))
.to.deep.equal(Buffer.from(AsnConvert.serialize(rootAsn.tbsCertificate.subject)));
expect(await leaf.verify({ publicKey: root })).to.equal(true);
expect(leaf.getExtension('1.3.6.1.4.1.11129.2.4.2') !== null)
.to.equal(certificateTransparency);
});
}
});
});