diff --git a/src/PKPass.ts b/src/PKPass.ts index 0ba649d..3ad867b 100644 --- a/src/PKPass.ts +++ b/src/PKPass.ts @@ -167,6 +167,8 @@ export default class PKPass extends Bundle { ); Object.assign(this[propsSymbol], overridesValidation); + + this.certificates = certificates; } /** @@ -491,8 +493,8 @@ export default class PKPass extends Bundle { } } - private [createManifestSymbol]() { - return Object.entries(this[filesSymbol]).reduce<{ + private [createManifestSymbol](): Buffer { + const manifest = Object.entries(this[filesSymbol]).reduce<{ [key: string]: string; }>((acc, [fileName, buffer]) => { const hashFlow = forge.md.sha1.create(); @@ -504,6 +506,8 @@ export default class PKPass extends Bundle { [fileName]: hashFlow.digest().toHex(), }; }, {}); + + return Buffer.from(JSON.stringify(manifest)); } private [closePassSymbol]() { @@ -576,10 +580,13 @@ export default class PKPass extends Bundle { } } - const manifest = this[createManifestSymbol](); - super.addBuffer("manifest.json", Buffer.from(JSON.stringify(manifest))); + const manifestBuffer = this[createManifestSymbol](); + super.addBuffer("manifest.json", manifestBuffer); - const signatureBuffer = Signature.create(manifest, this.certificates); + const signatureBuffer = Signature.create( + manifestBuffer, + this.certificates, + ); super.addBuffer("signature", signatureBuffer); } diff --git a/src/schemas/Certificates.ts b/src/schemas/Certificates.ts new file mode 100644 index 0000000..ad33494 --- /dev/null +++ b/src/schemas/Certificates.ts @@ -0,0 +1,18 @@ +import type forge from "node-forge"; +import Joi from "joi"; + +export interface CertificatesSchema { + wwdr: string | Buffer; + signerCert: string | Buffer; + signerKey: string | Buffer; + signerKeyPassphrase?: string; +} + +export const CertificatesSchema = Joi.object() + .keys({ + wwdr: Joi.alternatives(Joi.binary(), Joi.string()).required(), + signerCert: Joi.alternatives(Joi.binary(), Joi.string()).required(), + signerKey: Joi.alternatives(Joi.binary(), Joi.string()).required(), + signerKeyPassphrase: Joi.string(), + }) + .required(); diff --git a/src/schemas/index.ts b/src/schemas/index.ts index 8eb09a9..854023a 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -6,6 +6,7 @@ export * from "./NFC"; export * from "./SemanticTags"; export * from "./PassFields"; export * from "./Personalize"; +export * from "./Certificates"; import Joi from "joi"; import debug from "debug"; @@ -18,6 +19,7 @@ import { Field } from "./PassFieldContent"; import { PassFields, TransitType } from "./PassFields"; import { Personalization } from "./Personalize"; import { Semantics } from "./SemanticTags"; +import { CertificatesSchema } from "./Certificates"; const schemaDebug = debug("Schema"); @@ -25,33 +27,6 @@ export interface FileBuffers { [key: string]: Buffer; } -/* export interface Certificates { - wwdr?: string; - signerCert?: string; - signerKey?: - | { - keyFile: string; - passphrase?: string; - } - | string; -}*/ - -export interface CertificatesSchema { - wwdr: string | Buffer; - signerCert: string | Buffer; - signerKey: string | Buffer; - signerKeyPassphrase?: string; -} - -export const CertificatesSchema = Joi.object() - .keys({ - wwdr: Joi.alternatives(Joi.binary(), Joi.string()).required(), - signerCert: Joi.alternatives(Joi.binary(), Joi.string()).required(), - signerKey: Joi.alternatives(Joi.binary(), Joi.string()).required(), - signerKeyPassphrase: Joi.string(), - }) - .required(); - export interface PassProps { serialNumber?: string; description?: string; @@ -206,12 +181,6 @@ type AvailableSchemas = | typeof CertificatesSchema | typeof OverridablePassProps; -export type ArrayPassSchema = Beacon | Location | Barcode; - -/* function resolveSchemaName(name: Schema) { - return schemas[name] || undefined; -} - */ /** * Checks if the passed options are compliant with the indicated schema * @param {any} opts - options to be checks diff --git a/src/signature.ts b/src/signature.ts index 113ad42..555fa25 100644 --- a/src/signature.ts +++ b/src/signature.ts @@ -5,33 +5,25 @@ import type * as Schemas from "./schemas"; * Generates the PKCS #7 cryptografic signature for the manifest file. * * @method create - * @params manifest - Manifest content. + * @params manifest + * @params certificates * @returns */ export function create( - manifest: { [key: string]: string }, + manifestBuffer: Buffer, certificates: Schemas.CertificatesSchema, ): Buffer { const signature = forge.pkcs7.createSignedData(); - signature.content = forge.util.createBuffer( - JSON.stringify(manifest), - "utf8", + signature.content = forge.util.createBuffer(manifestBuffer.buffer, "utf8"); + + const { wwdr, signerCert, signerKey } = parseCertificates( + getStringCertificates(certificates), ); - const { wwdr, signerCert, signerKey, signerKeyPassphrase } = certificates; - - const wwdrString = wwdr instanceof Buffer ? wwdr.toString("utf-8") : wwdr; - const signerCertString = - signerCert instanceof Buffer - ? signerCert.toString("utf-8") - : signerCert; - const signerKeyString = - signerKey instanceof Buffer ? signerKey.toString("utf-8") : signerKey; - - signature.addCertificate(wwdrString); - signature.addCertificate(signerCertString); + signature.addCertificate(wwdr); + signature.addCertificate(signerCert); /** * authenticatedAttributes belong to PKCS#9 standard. @@ -43,8 +35,8 @@ export function create( */ signature.addSigner({ - key: signerKeyString, - certificate: signerCertString, + key: signerKey, + certificate: signerCert, digestAlgorithm: forge.pki.oids.sha1, authenticatedAttributes: [ { @@ -86,3 +78,35 @@ export function create( "binary", ); } + +/** + * Parses the PEM-formatted passed text (certificates) + * + * @param element - Text content of .pem files + * @param passphrase - passphrase for the key + * @returns The parsed certificate or key in node forge format + */ + +function parseCertificates(certificates: Schemas.CertificatesSchema) { + const { signerCert, signerKey, wwdr, signerKeyPassphrase } = certificates; + + return { + signerCert: forge.pki.certificateFromPem(signerCert.toString("utf-8")), + wwdr: forge.pki.certificateFromPem(wwdr.toString("utf-8")), + signerKey: forge.pki.decryptRsaPrivateKey( + signerKey.toString("utf-8"), + signerKeyPassphrase, + ), + }; +} + +function getStringCertificates( + certificates: Schemas.CertificatesSchema, +): Record { + return { + signerKeyPassphrase: certificates.signerKeyPassphrase, + wwdr: Buffer.from(certificates.wwdr).toString("utf-8"), + signerCert: Buffer.from(certificates.wwdr).toString("utf-8"), + signerKey: Buffer.from(certificates.wwdr).toString("utf-8"), + }; +}