Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 06cab68

Browse files
authoredJul 29, 2023
Fix pemToDer() return type (#364)
1 parent be61682 commit 06cab68

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
lines changed
 

‎src/signed-xml.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ export class SignedXml {
194194

195195
if (publicCertMatches.length > 0) {
196196
x509Certs = publicCertMatches
197-
.map((c) => `<X509Certificate>${utils.pemToDer(c)}</X509Certificate>`)
197+
.map((c) => `<X509Certificate>${utils.pemToDer(c).toString("base64")}</X509Certificate>`)
198198
.join("");
199199
}
200200

‎src/utils.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,18 @@ export function normalizePem(pem: string): string {
142142
/**
143143
* @param pem The PEM-encoded base64 certificate to strip headers from
144144
*/
145-
export function pemToDer(pem: string): string {
146-
return pem
147-
.replace(/(\r\n|\r)/g, "\n")
148-
.replace(/-----BEGIN [A-Z\x20]{1,48}-----\n?/, "")
149-
.replace(/-----END [A-Z\x20]{1,48}-----\n?/, "");
145+
export function pemToDer(pem: string): Buffer {
146+
if (!PEM_FORMAT_REGEX.test(pem.trim())) {
147+
throw new Error("Invalid PEM format.");
148+
}
149+
150+
return Buffer.from(
151+
pem
152+
.replace(/(\r\n|\r)/g, "")
153+
.replace(/-----BEGIN [A-Z\x20]{1,48}-----\n?/, "")
154+
.replace(/-----END [A-Z\x20]{1,48}-----\n?/, ""),
155+
"base64",
156+
);
150157
}
151158

152159
/**
@@ -155,15 +162,20 @@ export function pemToDer(pem: string): string {
155162
*/
156163
export function derToPem(
157164
der: string | Buffer,
158-
pemLabel: "CERTIFICATE" | "PRIVATE KEY" | "RSA PUBLIC KEY",
165+
pemLabel?: "CERTIFICATE" | "PRIVATE KEY" | "RSA PUBLIC KEY",
159166
): string {
160-
const base64Der = Buffer.isBuffer(der) ? der.toString("latin1").trim() : der.trim();
167+
const base64Der = Buffer.isBuffer(der)
168+
? der.toString("base64").trim()
169+
: der.replace(/(\r\n|\r)/g, "").trim();
161170

162171
if (PEM_FORMAT_REGEX.test(base64Der)) {
163172
return normalizePem(base64Der);
164173
}
165174

166175
if (BASE64_REGEX.test(base64Der)) {
176+
if (pemLabel == null) {
177+
throw new Error("PEM label is required when DER is given.");
178+
}
167179
const pem = `-----BEGIN ${pemLabel}-----\n${base64Der}\n-----END ${pemLabel}-----`;
168180

169181
return normalizePem(pem);

‎test/static/client_public.der

456 Bytes
Binary file not shown.

‎test/utils-tests.spec.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ describe("Utils tests", function () {
1212
pemAsArray[pemAsArray.length - 1]
1313
}`;
1414

15-
// @ts-expect-error FIXME
1615
expect(utils.derToPem(nonNormalizedPem)).to.equal(normalizedPem);
1716
});
1817

@@ -25,8 +24,45 @@ describe("Utils tests", function () {
2524
});
2625

2726
it("will throw if the format is neither PEM nor DER", function () {
28-
// @ts-expect-error FIXME
2927
expect(() => utils.derToPem("not a pem")).to.throw();
3028
});
29+
30+
it("will return a normalized PEM format when given a DER Buffer", function () {
31+
const normalizedPem = fs.readFileSync("./test/static/client_public.pem", "latin1");
32+
const derBuffer = fs.readFileSync("./test/static/client_public.der");
33+
34+
expect(utils.derToPem(derBuffer, "CERTIFICATE")).to.equal(normalizedPem);
35+
});
36+
37+
it("will return a normalized PEM format when given a base64 string with line breaks", function () {
38+
const normalizedPem = fs.readFileSync("./test/static/client_public.pem", "latin1");
39+
const base64String = fs.readFileSync("./test/static/client_public.der", "base64");
40+
41+
expect(utils.derToPem(base64String, "CERTIFICATE")).to.equal(normalizedPem);
42+
});
43+
44+
it("will throw if the DER string is not base64 encoded", function () {
45+
expect(() => utils.derToPem("not base64", "CERTIFICATE")).to.throw();
46+
});
47+
48+
it("will throw if the PEM label is not provided", function () {
49+
const derBuffer = fs.readFileSync("./test/static/client_public.der");
50+
expect(() => utils.derToPem(derBuffer)).to.throw();
51+
});
52+
});
53+
54+
describe("pemToDer", function () {
55+
it("will return a Buffer of binary DER when given a normalized PEM format", function () {
56+
const pem = fs.readFileSync("./test/static/client_public.pem", "latin1");
57+
const derBuffer = fs.readFileSync("./test/static/client_public.der");
58+
59+
const result = utils.pemToDer(pem);
60+
expect(result).to.be.instanceOf(Buffer);
61+
expect(result).to.deep.equal(derBuffer);
62+
});
63+
64+
it("will throw if the format is not PEM", function () {
65+
expect(() => utils.pemToDer("not a pem")).to.throw();
66+
});
3167
});
3268
});

0 commit comments

Comments
 (0)