Skip to content

Commit 05dc3e3

Browse files
authored
Merge pull request #124 from jaredwray/chore-getting-test-coverage-back-to-normal-levels
chore: getting test coverage back to normal levels
2 parents 1abdff0 + d3583e9 commit 05dc3e3

2 files changed

Lines changed: 74 additions & 2 deletions

File tree

src/certificate.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,10 @@ function derToPem(der: Buffer, label: string): string {
316316
return `-----BEGIN ${label}-----\n${lines.join("\n")}\n-----END ${label}-----\n`;
317317
}
318318

319+
// --- Exported for testing ---
320+
321+
export { encodeInteger as _encodeInteger, expandIpv6 as _expandIpv6 };
322+
319323
// --- Public API ---
320324

321325
/**
@@ -347,9 +351,19 @@ export function generateCertificate(
347351
notAfter.setDate(notAfter.getDate() + validityDays);
348352

349353
// Generate random serial number (16 bytes, positive)
350-
const serialNumber = crypto.randomBytes(16);
354+
const serialBytes = crypto.randomBytes(16);
351355
// Ensure positive by clearing the high bit
352-
serialNumber[0] &= 0x7f;
356+
serialBytes[0] &= 0x7f;
357+
// Strip leading zero bytes to produce minimal DER encoding,
358+
// but keep at least one byte
359+
let start = 0;
360+
/* v8 ignore start -- depends on random data producing leading zeros */
361+
while (start < serialBytes.length - 1 && serialBytes[start] === 0) {
362+
start++;
363+
}
364+
/* v8 ignore stop */
365+
366+
const serialNumber = serialBytes.subarray(start);
353367

354368
// Build TBS certificate
355369
const tbsCertificate = buildTbsCertificate(

test/certificate.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import * as path from "node:path";
55
import * as tls from "node:tls";
66
import { afterEach, describe, expect, test } from "vitest";
77
import {
8+
_encodeInteger,
9+
_expandIpv6,
810
generateCertificate,
911
generateCertificateFiles,
1012
} from "../src/certificate.js";
@@ -137,6 +139,62 @@ describe("generateCertificate", () => {
137139
});
138140
});
139141

142+
describe("encodeInteger", () => {
143+
test("should encode zero as a single zero byte", () => {
144+
const result = _encodeInteger(0);
145+
// DER INTEGER tag=0x02, length=1, value=0x00
146+
expect(result).toEqual(Buffer.from([0x02, 0x01, 0x00]));
147+
});
148+
149+
test("should add leading zero when high bit is set on number", () => {
150+
// 128 = 0x80, high bit is set so a leading 0x00 must be prepended
151+
const result = _encodeInteger(128);
152+
// DER INTEGER tag=0x02, length=2, value=0x00 0x80
153+
expect(result).toEqual(Buffer.from([0x02, 0x02, 0x00, 0x80]));
154+
});
155+
156+
test("should add leading zero when high bit is set on Buffer", () => {
157+
const buf = Buffer.from([0x80, 0x01]);
158+
const result = _encodeInteger(buf);
159+
// DER INTEGER tag=0x02, length=3, value=0x00 0x80 0x01
160+
expect(result).toEqual(Buffer.from([0x02, 0x03, 0x00, 0x80, 0x01]));
161+
});
162+
});
163+
164+
describe("expandIpv6", () => {
165+
test("should pad groups in a fully-expanded IPv6 address", () => {
166+
const result = _expandIpv6("2001:db8:0:0:0:0:0:1");
167+
expect(result).toBe("2001:0db8:0000:0000:0000:0000:0000:0001");
168+
});
169+
170+
test("should expand :: with empty left side", () => {
171+
const result = _expandIpv6("::1");
172+
expect(result).toBe("0000:0000:0000:0000:0000:0000:0000:0001");
173+
});
174+
175+
test("should expand :: with empty right side", () => {
176+
const result = _expandIpv6("fe80::");
177+
expect(result).toBe("fe80:0000:0000:0000:0000:0000:0000:0000");
178+
});
179+
180+
test("should expand :: in the middle of an address", () => {
181+
const result = _expandIpv6("2001:db8::1");
182+
expect(result).toBe("2001:0db8:0000:0000:0000:0000:0000:0001");
183+
});
184+
});
185+
186+
describe("generateCertificate with fully-expanded IPv6", () => {
187+
test("should handle a fully-expanded IPv6 altName without ::", () => {
188+
const result = generateCertificate({
189+
altNames: [
190+
{ type: "ip", value: "2001:0db8:0000:0000:0000:0000:0000:0001" },
191+
],
192+
});
193+
const x509 = new crypto.X509Certificate(result.cert);
194+
expect(x509.subjectAltName).toContain("IP Address:2001:DB8");
195+
});
196+
});
197+
140198
describe("generateCertificateFiles", () => {
141199
let tmpDir: string;
142200

0 commit comments

Comments
 (0)