( mcpbPath: string, )
| 101 | * @returns Signature information including verification status |
| 102 | */ |
| 103 | export async function verifyMcpbFile( |
| 104 | mcpbPath: string, |
| 105 | ): Promise<z.infer<typeof McpbSignatureInfoSchema>> { |
| 106 | try { |
| 107 | const fileContent = readFileSync(mcpbPath); |
| 108 | |
| 109 | // Find and extract signature block |
| 110 | const { originalContent, pkcs7Signature } = |
| 111 | extractSignatureBlock(fileContent); |
| 112 | if (!pkcs7Signature) { |
| 113 | return { status: "unsigned" }; |
| 114 | } |
| 115 | |
| 116 | // Parse PKCS#7 signature |
| 117 | const asn1 = forge.asn1.fromDer(pkcs7Signature.toString("binary")); |
| 118 | const p7Message = forge.pkcs7.messageFromAsn1(asn1); |
| 119 | |
| 120 | // Verify it's signed data and cast to correct type |
| 121 | if ( |
| 122 | !("type" in p7Message) || |
| 123 | p7Message.type !== forge.pki.oids.signedData |
| 124 | ) { |
| 125 | return { status: "unsigned" }; |
| 126 | } |
| 127 | |
| 128 | // Now we know it's PkcsSignedData. The types are incorrect, so we'll |
| 129 | // fix them there |
| 130 | const p7 = p7Message as unknown as forge.pkcs7.PkcsSignedData & { |
| 131 | signerInfos: Array<{ |
| 132 | authenticatedAttributes: Array<{ |
| 133 | type: string; |
| 134 | value: unknown; |
| 135 | }>; |
| 136 | }>; |
| 137 | verify: (options?: { authenticatedAttributes?: boolean }) => boolean; |
| 138 | }; |
| 139 | |
| 140 | // Extract certificates from PKCS#7 |
| 141 | const certificates = p7.certificates || []; |
| 142 | if (certificates.length === 0) { |
| 143 | return { status: "unsigned" }; |
| 144 | } |
| 145 | |
| 146 | // Get the signing certificate (first one) |
| 147 | const signingCert = certificates[0]; |
| 148 | |
| 149 | // Verify PKCS#7 signature |
| 150 | const contentBuf = forge.util.createBuffer(originalContent); |
| 151 | |
| 152 | try { |
| 153 | p7.verify({ authenticatedAttributes: true }); |
| 154 | |
| 155 | // Also verify the content matches |
| 156 | const signerInfos = p7.signerInfos; |
| 157 | const signerInfo = signerInfos?.[0]; |
| 158 | if (signerInfo) { |
| 159 | const md = forge.md.sha256.create(); |
| 160 | md.update(contentBuf.getBytes()); |
searching dependent graphs…