Certificate Verification
Working with APK signing certificates.
Basic Certificate Access
typescript
import { Apk } from "node-apk";
const apk = new Apk("app.apk");
const certs = await apk.getCertificateInfo();
for (const cert of certs) {
console.log("Certificate:");
console.log(` Subject: ${cert.subject.get("CN")}`);
console.log(` Issuer: ${cert.issuer.get("CN")}`);
console.log(` Serial: ${cert.serial}`);
console.log(` Valid from: ${cert.validFrom}`);
console.log(` Valid until: ${cert.validUntil}`);
}Certificate Chain Traversal
typescript
const apk = new Apk("app.apk");
const certs = await apk.getCertificateInfo();
for (const cert of certs) {
console.log("\nCertificate Chain:");
for (let i = 0; i < cert.chain.length; i++) {
const c = cert.chain[i];
const indent = " ".repeat(i);
console.log(`${indent}${i + 1}. ${c.subject.get("CN")}`);
}
}Validity Checking
typescript
function checkCertificateValidity(cert: Certificate): {
valid: boolean;
expired: boolean;
notYetValid: boolean;
daysUntilExpiry: number;
} {
const now = new Date();
return {
valid: now >= cert.validFrom && now <= cert.validUntil,
expired: now > cert.validUntil,
notYetValid: now < cert.validFrom,
daysUntilExpiry: Math.floor(
(cert.validUntil.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
),
};
}
// Usage
const apk = new Apk("app.apk");
const certs = await apk.getCertificateInfo();
for (const cert of certs) {
const status = checkCertificateValidity(cert);
if (status.expired) {
console.error(`❌ Certificate expired!`);
} else if (status.notYetValid) {
console.warn(`⚠️ Certificate not yet valid`);
} else {
console.log(`✅ Valid for ${status.daysUntilExpiry} more days`);
}
}Fingerprint Calculation
typescript
import { createHash } from "node:crypto";
function getFingerprints(cert: Certificate) {
return {
sha256: createHash("sha256")
.update(cert.bytes)
.digest("hex")
.match(/.{2}/g)
?.join(":") ?? "",
sha1: createHash("sha1")
.update(cert.bytes)
.digest("hex")
.match(/.{2}/g)
?.join(":") ?? "",
md5: createHash("md5")
.update(cert.bytes)
.digest("hex")
.match(/.{2}/g)
?.join(":") ?? "",
};
}
// Usage
const apk = new Apk("app.apk");
const certs = await apk.getCertificateInfo();
for (const cert of certs) {
const prints = getFingerprints(cert);
console.log(`SHA-256: ${prints.sha256}`);
console.log(`SHA-1: ${prints.sha1}`);
}Certificate Comparison
Compare certificates to verify APK authenticity:
typescript
function certificatesEqual(cert1: Certificate, cert2: Certificate): boolean {
return cert1.bytes.equals(cert2.bytes);
}
async function verifyApkSignature(
apkPath: string,
expectedCertPath: string
): Promise<boolean> {
const apk = new Apk(apkPath);
const certs = await apk.getCertificateInfo();
const expectedCert = Certificate.fromDer(
await fs.readFile(expectedCertPath)
)[0];
return certs.some(cert => certificatesEqual(cert, expectedCert));
}
// Usage
const isValid = await verifyApkSignature("app.apk", "expected-cert.der");
if (!isValid) {
console.error("APK signature mismatch!");
}PEM Export
Convert certificate to PEM format:
typescript
function toPem(cert: Certificate): string {
const base64 = cert.bytes.toString("base64");
const lines = base64.match(/.{1,64}/g) ?? [];
return [
"-----BEGIN CERTIFICATE-----",
...lines,
"-----END CERTIFICATE-----",
].join("\n");
}
// Usage
const apk = new Apk("app.apk");
const certs = await apk.getCertificateInfo();
for (const cert of certs) {
const pem = toPem(cert);
await fs.writeFile(`${cert.subject.get("CN")}.pem`, pem);
}Self-Signed vs CA-Signed
typescript
function isSelfSigned(cert: Certificate): boolean {
// A certificate is self-signed if issuer == subject
return !cert.parent;
}
const apk = new Apk("app.apk");
const certs = await apk.getCertificateInfo();
for (const cert of certs) {
if (isSelfSigned(cert)) {
console.log("Self-signed certificate");
} else {
console.log(`Signed by: ${cert.parent?.subject.get("CN")}`);
}
}Certificate Information Summary
typescript
function getCertificateSummary(cert: Certificate) {
return {
subject: {
commonName: cert.subject.get("CN"),
organization: cert.subject.get("O"),
country: cert.subject.get("C"),
},
issuer: {
commonName: cert.issuer.get("CN"),
organization: cert.issuer.get("O"),
},
validity: {
from: cert.validFrom.toISOString(),
until: cert.validUntil.toISOString(),
daysRemaining: Math.floor(
(cert.validUntil.getTime() - Date.now()) / (1000 * 60 * 60 * 24)
),
},
chainLength: cert.chain.length,
fingerprintSha256: createHash("sha256")
.update(cert.bytes)
.digest("hex"),
};
}Related
- Certificate API - API reference
- Basic Usage - Getting started