File Coverage

src/pdfmake_pkcs12.c
Criterion Covered Total %
statement 378 646 58.5
branch 190 528 35.9
condition n/a
subroutine n/a
pod n/a
total 568 1174 48.3


line stmt bran cond sub pod time code
1             /*
2             * pdfmake_pkcs12.c — PKCS#12/PFX parsing implementation
3             *
4             * Parse PKCS#12 containers to extract signing identities.
5             *
6             * Note: Full PKCS#12 parsing requires complex password-based encryption.
7             * This is a simplified implementation that handles common cases.
8             * For production use, consider linking against OpenSSL or similar.
9             */
10              
11             #include "pdfmake_pkcs12.h"
12             #include "pdfmake_asn1.h"
13             #include "pdfmake_x509.h"
14             #include "pdfmake_arena.h"
15             #include "pdfmake_aes.h"
16             #include
17             #include
18             #include
19              
20             /*============================================================================
21             * PKCS#12 Key Derivation (simplified - SHA1 based)
22             *==========================================================================*/
23              
24             /* PKCS#12 uses a specific KDF based on SHA-1 (RFC 7292, Appendix B) */
25             /* This is a simplified implementation for the most common case */
26              
27             /* Simple SHA-1 implementation for PKCS#12 KDF */
28             /* For production, use a proper crypto library */
29              
30             typedef struct {
31             uint32_t state[5];
32             uint64_t count;
33             uint8_t buffer[64];
34             } sha1_ctx_t;
35              
36 12288           static void sha1_init(sha1_ctx_t *ctx)
37             {
38 12288           ctx->state[0] = 0x67452301;
39 12288           ctx->state[1] = 0xEFCDAB89;
40 12288           ctx->state[2] = 0x98BADCFE;
41 12288           ctx->state[3] = 0x10325476;
42 12288           ctx->state[4] = 0xC3D2E1F0;
43 12288           ctx->count = 0;
44 12288           }
45              
46             #define ROL32(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
47              
48 12306           static void sha1_transform(uint32_t state[5], const uint8_t block[64])
49             {
50             uint32_t a, b, c, d, e;
51             uint32_t f, k;
52             uint32_t temp;
53             uint32_t w[80];
54             int i;
55            
56             /* Expand block */
57 209202 100         for (i = 0; i < 16; i++) {
58 196896           w[i] = ((uint32_t)block[i*4] << 24) |
59 196896           ((uint32_t)block[i*4+1] << 16) |
60 196896           ((uint32_t)block[i*4+2] << 8) |
61 196896           ((uint32_t)block[i*4+3]);
62             }
63 799890 100         for (i = 16; i < 80; i++) {
64 787584           w[i] = ROL32(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
65             }
66            
67 12306           a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4];
68            
69 996786 100         for (i = 0; i < 80; i++) {
70 984480 100         if (i < 20) {
71 246120           f = (b & c) | ((~b) & d);
72 246120           k = 0x5A827999;
73 738360 100         } else if (i < 40) {
74 246120           f = b ^ c ^ d;
75 246120           k = 0x6ED9EBA1;
76 492240 100         } else if (i < 60) {
77 246120           f = (b & c) | (b & d) | (c & d);
78 246120           k = 0x8F1BBCDC;
79             } else {
80 246120           f = b ^ c ^ d;
81 246120           k = 0xCA62C1D6;
82             }
83            
84 984480           temp = ROL32(a, 5) + f + e + k + w[i];
85 984480           e = d; d = c; c = ROL32(b, 30); b = a; a = temp;
86             }
87            
88 12306           state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e;
89 12306           }
90              
91 36864           static void sha1_update(sha1_ctx_t *ctx, const uint8_t *data, size_t len)
92             {
93 36864           size_t i = (ctx->count >> 3) & 63;
94             size_t part_len;
95 36864           size_t j = 0;
96 36864           ctx->count += (uint64_t)len << 3;
97            
98 36864           part_len = 64 - i;
99            
100 36864 100         if (len >= part_len) {
101 12294           memcpy(ctx->buffer + i, data, part_len);
102 12294           sha1_transform(ctx->state, ctx->buffer);
103            
104 12306 100         for (j = part_len; j + 63 < len; j += 64) {
105 12           sha1_transform(ctx->state, data + j);
106             }
107 12294           i = 0;
108             }
109            
110 36864           memcpy(ctx->buffer + i, data + j, len - j);
111 36864           }
112              
113 12288           static void sha1_final(sha1_ctx_t *ctx, uint8_t digest[20])
114             {
115 12288           uint8_t pad[64] = {0x80};
116 12288           uint64_t bits = ctx->count;
117             size_t i;
118             size_t pad_len;
119             uint8_t len_bytes[8];
120             int j;
121            
122 12288           i = (ctx->count >> 3) & 63;
123 12288 50         pad_len = (i < 56) ? (56 - i) : (120 - i);
124            
125 12288           sha1_update(ctx, pad, pad_len);
126            
127 110592 100         for (j = 0; j < 8; j++) {
128 98304           len_bytes[j] = (bits >> (56 - j * 8)) & 0xFF;
129             }
130 12288           sha1_update(ctx, len_bytes, 8);
131            
132 73728 100         for (j = 0; j < 5; j++) {
133 61440           digest[j*4] = (ctx->state[j] >> 24) & 0xFF;
134 61440           digest[j*4+1] = (ctx->state[j] >> 16) & 0xFF;
135 61440           digest[j*4+2] = (ctx->state[j] >> 8) & 0xFF;
136 61440           digest[j*4+3] = ctx->state[j] & 0xFF;
137             }
138 12288           }
139              
140 12288           static void sha1(const uint8_t *data, size_t len, uint8_t digest[20])
141             {
142             sha1_ctx_t ctx;
143 12288           sha1_init(&ctx);
144 12288           sha1_update(&ctx, data, len);
145 12288           sha1_final(&ctx, digest);
146 12288           }
147              
148             /*
149             * PKCS#12 Password-Based Key Derivation (RFC 7292 Appendix B)
150             *
151             * This derives key material from a password and salt.
152             * ID values: 1 = key, 2 = IV, 3 = MAC key
153             */
154 4           static void pkcs12_kdf(
155             const char *password,
156             const uint8_t *salt,
157             size_t salt_len,
158             int iterations,
159             int id,
160             uint8_t *output,
161             size_t output_len)
162             {
163 4           const int u = 20; /* SHA-1 output size */
164 4           const int v = 64; /* SHA-1 block size */
165             size_t S_len;
166             uint8_t *S;
167             size_t pwd_len;
168             size_t P_raw_len;
169             size_t P_len;
170             uint8_t *P;
171             size_t I_len;
172             uint8_t *I;
173             size_t produced;
174             uint8_t *A;
175             uint8_t *B;
176             uint8_t *DI;
177             size_t i;
178             int j;
179             size_t jj;
180             int k;
181             size_t to_copy;
182            
183             /* Construct D (diversifier) */
184             uint8_t D[64];
185 4           memset(D, id, v);
186            
187             /* Construct S (salt, padded to v bytes) */
188 4           S_len = ((salt_len + v - 1) / v) * v;
189 4 50         if (S_len == 0) S_len = v;
190 4           S = calloc(S_len, 1);
191 4 50         if (!S) return;
192 260 100         for (i = 0; i < S_len; i++) {
193 256 50         S[i] = salt_len > 0 ? salt[i % salt_len] : 0;
194             }
195            
196             /* Construct P (password as BMPString, padded to v bytes) */
197 4 50         pwd_len = password ? strlen(password) : 0;
198 4           P_raw_len = (pwd_len + 1) * 2; /* UTF-16BE with null */
199 4           P_len = ((P_raw_len + v - 1) / v) * v;
200 4 50         if (P_len == 0) P_len = v;
201 4           P = calloc(P_len, 1);
202 4 50         if (!P) { free(S); return; }
203            
204 36 100         for (i = 0; i < pwd_len; i++) {
205 32           P[i*2] = 0;
206 32           P[i*2+1] = (uint8_t)password[i];
207             }
208             /* Null terminator */
209 4           P[pwd_len*2] = 0;
210 4           P[pwd_len*2+1] = 0;
211            
212             /* Repeat P to fill P_len */
213 188 100         for (i = P_raw_len; i < P_len; i++) {
214 184           P[i] = P[i % P_raw_len];
215             }
216            
217             /* Construct I = S || P */
218 4           I_len = S_len + P_len;
219 4           I = malloc(I_len);
220 4 50         if (!I) { free(S); free(P); return; }
221 4           memcpy(I, S, S_len);
222 4           memcpy(I + S_len, P, P_len);
223            
224             /* Generate output */
225 4           produced = 0;
226 4           A = malloc(u);
227 4           B = malloc(v);
228 4           DI = malloc(v + I_len);
229            
230 4 50         if (!A || !B || !DI) {
    50          
    50          
231 0           free(S); free(P); free(I);
232 0 0         if (A) free(A);
233 0 0         if (B) free(B);
234 0 0         if (DI) free(DI);
235 0           return;
236             }
237            
238 6 50         while (produced < output_len) {
239             /* A = Hash(D || I), iterated */
240 6           memcpy(DI, D, v);
241 6           memcpy(DI + v, I, I_len);
242 6           sha1(DI, v + I_len, A);
243            
244 12288 100         for (j = 1; j < iterations; j++) {
245 12282           sha1(A, u, A);
246             }
247            
248             /* Copy to output */
249 6           to_copy = output_len - produced;
250 6 100         if (to_copy > (size_t)u) to_copy = u;
251 6           memcpy(output + produced, A, to_copy);
252 6           produced += to_copy;
253            
254 6 100         if (produced >= output_len) break;
255            
256             /* Construct B by repeating A */
257 130 100         for (j = 0; j < v; j++) {
258 128           B[j] = A[j % u];
259             }
260            
261             /* I = I + B + 1 (treating I as concatenation of v-byte integers) */
262 6 100         for (jj = 0; jj < I_len; jj += v) {
263 4           uint16_t carry = 1;
264             uint16_t sum;
265 260 100         for (k = v - 1; k >= 0; k--) {
266 256           sum = (uint16_t)I[jj + k] + B[k] + carry;
267 256           I[jj + k] = sum & 0xFF;
268 256           carry = sum >> 8;
269             }
270             }
271             }
272            
273 4           free(S);
274 4           free(P);
275 4           free(I);
276 4           free(A);
277 4           free(B);
278 4           free(DI);
279             }
280              
281             /*============================================================================
282             * 3DES-CBC Decryption (for PKCS#12)
283             *==========================================================================*/
284              
285             /* Simple 3DES implementation for PKCS#12 decryption */
286             /* For production, use a proper crypto library */
287              
288             /* DES S-boxes */
289             static const uint8_t DES_SBOX[8][64] = {
290             {14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
291             4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13},
292             {15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
293             0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9},
294             {10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
295             13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12},
296             {7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
297             10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14},
298             {2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
299             4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3},
300             {12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
301             9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13},
302             {4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
303             1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12},
304             {13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,
305             7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}
306             };
307              
308             /* DES permutation tables */
309             static const uint8_t DES_IP[64] = {
310             58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,
311             62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,
312             57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,
313             61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7
314             };
315              
316             static const uint8_t DES_FP[64] = {
317             40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,
318             38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,
319             36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,
320             34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25
321             };
322              
323             static const uint8_t DES_E[48] = {
324             32,1,2,3,4,5,4,5,6,7,8,9,8,9,10,11,12,13,12,13,14,15,16,17,
325             16,17,18,19,20,21,20,21,22,23,24,25,24,25,26,27,28,29,28,29,30,31,32,1
326             };
327              
328             static const uint8_t DES_P[32] = {
329             16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,
330             2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25
331             };
332              
333             static const uint8_t DES_PC1[56] = {
334             57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,
335             63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4
336             };
337              
338             static const uint8_t DES_PC2[48] = {
339             14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,
340             41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32
341             };
342              
343             static const uint8_t DES_SHIFTS[16] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
344              
345             /* Single DES round */
346 13008           static uint32_t des_f(uint32_t R, const uint8_t K[6])
347             {
348             /* Expand R to 48 bits */
349 13008           uint8_t E[6] = {0};
350 13008           uint32_t S_out = 0;
351 13008           uint32_t P_out = 0;
352             int i;
353             int bit;
354             int bits;
355             int row;
356             int col;
357 637392 100         for (i = 0; i < 48; i++) {
358 624384           bit = (R >> (32 - DES_E[i])) & 1;
359 624384           E[i/8] |= bit << (7 - i%8);
360             }
361            
362             /* XOR with key */
363 91056 100         for (i = 0; i < 6; i++) E[i] ^= K[i];
364            
365             /* S-box substitution */
366 117072 100         for (i = 0; i < 8; i++) {
367 104064           bits = (E[i*6/8] << 8 | E[i*6/8+1]) >> (10 - i*6%8);
368 104064           row = ((bits >> 5) & 1) * 2 + (bits & 1);
369 104064           col = (bits >> 1) & 0xF;
370 104064           S_out = (S_out << 4) | DES_SBOX[i][row * 16 + col];
371             }
372            
373             /* P permutation */
374 429264 100         for (i = 0; i < 32; i++) {
375 416256           P_out |= ((S_out >> (32 - DES_P[i])) & 1) << (31 - i);
376             }
377            
378 13008           return P_out;
379             }
380              
381             /* Generate DES subkeys */
382 6           static void des_keysched(const uint8_t key[8], uint8_t subkeys[16][6])
383             {
384             /* PC1 permutation */
385 6           uint64_t pc1 = 0;
386             uint32_t C;
387             uint32_t D;
388             int i;
389             int round;
390             int bit;
391             uint64_t CD;
392 342 100         for (i = 0; i < 56; i++) {
393 336           bit = (key[(DES_PC1[i]-1)/8] >> (7 - (DES_PC1[i]-1)%8)) & 1;
394 336           pc1 |= (uint64_t)bit << (55 - i);
395             }
396            
397 6           C = pc1 >> 28;
398 6           D = pc1 & 0xFFFFFFF;
399            
400 102 100         for (round = 0; round < 16; round++) {
401             /* Left rotate */
402 264 100         for (i = 0; i < DES_SHIFTS[round]; i++) {
403 168           C = ((C << 1) | (C >> 27)) & 0xFFFFFFF;
404 168           D = ((D << 1) | (D >> 27)) & 0xFFFFFFF;
405             }
406            
407             /* PC2 permutation */
408 96           CD = ((uint64_t)C << 28) | D;
409 4704 100         for (i = 0; i < 48; i++) {
410 4608           bit = (CD >> (56 - DES_PC2[i])) & 1;
411 4608 100         if (bit) {
412 2302           subkeys[round][i/8] |= 1 << (7 - i%8);
413             } else {
414 2306           subkeys[round][i/8] &= ~(1 << (7 - i%8));
415             }
416             }
417             }
418 6           }
419              
420             /* DES block core (shared by encrypt and decrypt) */
421 813           static void des_block_core(const uint8_t in[8], const uint8_t subkeys[16][6],
422             int decrypt, uint8_t out[8])
423             {
424             /* IP permutation */
425 813           uint64_t ip = 0;
426             uint32_t L;
427             uint32_t R;
428             uint64_t RL;
429             int i;
430             int bit;
431             int round;
432             uint32_t temp;
433 52845 100         for (i = 0; i < 64; i++) {
434 52032           bit = (in[(DES_IP[i]-1)/8] >> (7 - (DES_IP[i]-1)%8)) & 1;
435 52032           ip |= (uint64_t)bit << (63 - i);
436             }
437              
438 813           L = ip >> 32;
439 813           R = ip & 0xFFFFFFFF;
440              
441             /* 16 rounds */
442 13821 100         for (i = 0; i < 16; i++) {
443 13008 100         round = decrypt ? (15 - i) : i;
444 13008           temp = R;
445 13008           R = L ^ des_f(R, subkeys[round]);
446 13008           L = temp;
447             }
448              
449             /* FP permutation (note: swap L/R) */
450 813           RL = ((uint64_t)R << 32) | L;
451 813           memset(out, 0, 8);
452 52845 100         for (i = 0; i < 64; i++) {
453 52032           bit = (RL >> (64 - DES_FP[i])) & 1;
454 52032 100         if (bit)
455 26041           out[i/8] |= 1 << (7 - i%8);
456             }
457 813           }
458              
459             /* Single DES block encrypt */
460 271           static void des_encrypt_block(const uint8_t in[8], const uint8_t subkeys[16][6], uint8_t out[8])
461             {
462 271           des_block_core(in, subkeys, 0, out);
463 271           }
464              
465             /* Single DES block decrypt */
466 542           static void des_decrypt_block(const uint8_t in[8], const uint8_t subkeys[16][6], uint8_t out[8])
467             {
468 542           des_block_core(in, subkeys, 1, out);
469 542           }
470              
471             /* 3DES-EDE3-CBC decrypt */
472 2           static void des3_cbc_decrypt(
473             const uint8_t *in, size_t len,
474             const uint8_t key[24],
475             const uint8_t iv[8],
476             uint8_t *out)
477             {
478             uint8_t sk1[16][6], sk2[16][6], sk3[16][6];
479             uint8_t prev[8];
480             size_t i;
481             int j;
482             uint8_t t1[8], t2[8];
483 2           memset(sk1, 0, sizeof(sk1));
484 2           memset(sk2, 0, sizeof(sk2));
485 2           memset(sk3, 0, sizeof(sk3));
486 2           des_keysched(key, sk1);
487 2           des_keysched(key + 8, sk2);
488 2           des_keysched(key + 16, sk3);
489              
490 2           memcpy(prev, iv, 8);
491              
492 273 100         for (i = 0; i < len; i += 8) {
493              
494             /* 3DES-EDE3 decrypt: D(K1, E(K2, D(K3, block))) */
495 271           des_decrypt_block(in + i, sk3, t1);
496 271           des_encrypt_block(t1, sk2, t2);
497 271           des_decrypt_block(t2, sk1, out + i);
498              
499             /* CBC: XOR with previous ciphertext */
500 2439 100         for (j = 0; j < 8; j++)
501 2168           out[i + j] ^= prev[j];
502              
503 271           memcpy(prev, in + i, 8);
504             }
505 2           }
506              
507             /*============================================================================
508             * Base64 Decoding (for PEM)
509             *==========================================================================*/
510              
511             static const int8_t b64_table[256] = {
512             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
513             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
514             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
515             52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,
516             -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
517             15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
518             -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
519             41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
520             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
521             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
522             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
523             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
524             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
525             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
526             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
527             -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
528             };
529              
530 0           static size_t base64_decode(const char *src, size_t src_len, uint8_t *dst, size_t dst_len)
531             {
532 0           size_t out = 0;
533 0           uint32_t accum = 0;
534 0           int bits = 0;
535             size_t i;
536             int8_t val;
537            
538 0 0         for (i = 0; i < src_len && out < dst_len; i++) {
    0          
539 0           val = b64_table[(uint8_t)src[i]];
540 0 0         if (val == -1) continue;
541 0 0         if (val == -2) break;
542            
543 0           accum = (accum << 6) | val;
544 0           bits += 6;
545            
546 0 0         if (bits >= 8) {
547 0           bits -= 8;
548 0           dst[out++] = (accum >> bits) & 0xFF;
549             }
550             }
551            
552 0           return out;
553             }
554              
555             /*============================================================================
556             * PKCS#8 Private Key Parsing
557             *==========================================================================*/
558              
559 1           pdfmake_privkey_t *pdfmake_pkcs8_parse_der(
560             pdfmake_arena_t *arena,
561             const uint8_t *data,
562             size_t len)
563             {
564             pdfmake_asn1_node_t *root;
565             pdfmake_asn1_node_t *version;
566             pdfmake_asn1_node_t *alg;
567             pdfmake_asn1_node_t *key_data;
568             pdfmake_asn1_node_t *oid_node;
569             char *oid;
570             pdfmake_privkey_t *key;
571             size_t pos;
572             pdfmake_asn1_node_t *rsa_key;
573             pdfmake_asn1_node_t *n;
574             pdfmake_asn1_node_t *e;
575             pdfmake_asn1_node_t *d;
576             pdfmake_asn1_node_t *p;
577             pdfmake_asn1_node_t *q;
578             pdfmake_asn1_node_t *param;
579             pdfmake_asn1_node_t *ec_key;
580             pdfmake_asn1_node_t *priv;
581             pdfmake_asn1_node_t *child;
582              
583 1 50         if (!arena || !data || len == 0) return NULL;
    50          
    50          
584            
585             /* Parse ASN.1 */
586 1           root = pdfmake_asn1_parse(arena, data, len);
587 1 50         if (!pdfmake_asn1_is_sequence(root)) {
588 0           return NULL;
589             }
590            
591             /* PrivateKeyInfo ::= SEQUENCE {
592             version Version,
593             privateKeyAlgorithm AlgorithmIdentifier,
594             privateKey OCTET STRING,
595             attributes [0] IMPLICIT Attributes OPTIONAL } */
596            
597 1           version = pdfmake_asn1_child_at(root, 0);
598 1           alg = pdfmake_asn1_child_at(root, 1);
599 1           key_data = pdfmake_asn1_child_at(root, 2);
600            
601 1 50         if (!version || !alg || !key_data) return NULL;
    50          
    50          
602            
603             /* Get algorithm OID */
604 1           oid_node = pdfmake_asn1_child_at(alg, 0);
605 1 50         if (!oid_node) return NULL;
606            
607 1           oid = pdfmake_asn1_get_oid_string(arena, oid_node);
608 1 50         if (!oid) return NULL;
609            
610             /* Allocate private key structure */
611 1           key = pdfmake_arena_alloc(arena, sizeof(pdfmake_privkey_t));
612 1 50         if (!key) return NULL;
613 1           memset(key, 0, sizeof(pdfmake_privkey_t));
614            
615             /* Store raw PKCS#8 */
616 1           key->pkcs8_der = pdfmake_arena_alloc(arena, len);
617 1 50         if (key->pkcs8_der) {
618 1           memcpy(key->pkcs8_der, data, len);
619 1           key->pkcs8_der_len = len;
620             }
621            
622 1 50         if (strcmp(oid, OID_RSA_ENCRYPTION) == 0) {
623 1           key->algorithm = PDFMAKE_PK_RSA;
624            
625             /* Parse RSA private key from OCTET STRING */
626 1 50         if (key_data->tag == ASN1_TAG_OCTET_STRING) {
627 1           pos = 0;
628 1           rsa_key = pdfmake_asn1_parse_element(
629             arena, key_data->data, key_data->length, &pos);
630            
631 1 50         if (pdfmake_asn1_is_sequence(rsa_key)) {
632             /* RSAPrivateKey ::= SEQUENCE {
633             version, modulus, publicExponent, privateExponent,
634             prime1, prime2, exponent1, exponent2, coefficient } */
635            
636 1           n = pdfmake_asn1_child_at(rsa_key, 1); /* modulus */
637 1           e = pdfmake_asn1_child_at(rsa_key, 2); /* publicExponent */
638 1           d = pdfmake_asn1_child_at(rsa_key, 3); /* privateExponent */
639 1           p = pdfmake_asn1_child_at(rsa_key, 4); /* prime1 */
640 1           q = pdfmake_asn1_child_at(rsa_key, 5); /* prime2 */
641            
642 1 50         if (n && e && d) {
    50          
    50          
643 1           key->rsa.modulus = pdfmake_arena_alloc(arena, n->length);
644 1 50         if (key->rsa.modulus) {
645 1           memcpy(key->rsa.modulus, n->data, n->length);
646 1           key->rsa.modulus_len = n->length;
647             }
648            
649 1           key->rsa.public_exponent = pdfmake_arena_alloc(arena, e->length);
650 1 50         if (key->rsa.public_exponent) {
651 1           memcpy(key->rsa.public_exponent, e->data, e->length);
652 1           key->rsa.public_exponent_len = e->length;
653             }
654            
655 1           key->rsa.private_exponent = pdfmake_arena_alloc(arena, d->length);
656 1 50         if (key->rsa.private_exponent) {
657 1           memcpy(key->rsa.private_exponent, d->data, d->length);
658 1           key->rsa.private_exponent_len = d->length;
659             }
660            
661 1 50         if (p) {
662 1           key->rsa.prime1 = pdfmake_arena_alloc(arena, p->length);
663 1 50         if (key->rsa.prime1) {
664 1           memcpy(key->rsa.prime1, p->data, p->length);
665 1           key->rsa.prime1_len = p->length;
666             }
667             }
668            
669 1 50         if (q) {
670 1           key->rsa.prime2 = pdfmake_arena_alloc(arena, q->length);
671 1 50         if (key->rsa.prime2) {
672 1           memcpy(key->rsa.prime2, q->data, q->length);
673 1           key->rsa.prime2_len = q->length;
674             }
675             }
676             }
677             }
678             }
679 0 0         } else if (strcmp(oid, OID_EC_PUBLIC_KEY) == 0) {
680 0           key->algorithm = PDFMAKE_PK_ECDSA;
681            
682             /* Get curve OID from algorithm parameters */
683 0           param = pdfmake_asn1_child_at(alg, 1);
684 0 0         if (param && param->tag == ASN1_TAG_OID) {
    0          
685 0           key->ecdsa.curve_oid = pdfmake_asn1_get_oid_string(arena, param);
686            
687 0 0         if (pdfmake_asn1_oid_equals(param, OID_SECP256R1)) {
688 0           key->ecdsa.curve_bits = 256;
689 0 0         } else if (pdfmake_asn1_oid_equals(param, OID_SECP384R1)) {
690 0           key->ecdsa.curve_bits = 384;
691 0 0         } else if (pdfmake_asn1_oid_equals(param, OID_SECP521R1)) {
692 0           key->ecdsa.curve_bits = 521;
693             }
694             }
695            
696             /* Parse EC private key from OCTET STRING */
697 0 0         if (key_data->tag == ASN1_TAG_OCTET_STRING) {
698 0           pos = 0;
699 0           ec_key = pdfmake_asn1_parse_element(
700             arena, key_data->data, key_data->length, &pos);
701            
702 0 0         if (pdfmake_asn1_is_sequence(ec_key)) {
703             /* ECPrivateKey ::= SEQUENCE {
704             version INTEGER,
705             privateKey OCTET STRING,
706             parameters [0] EXPLICIT ECParameters OPTIONAL,
707             publicKey [1] EXPLICIT BIT STRING OPTIONAL } */
708            
709 0           priv = pdfmake_asn1_child_at(ec_key, 1);
710 0 0         if (priv && priv->tag == ASN1_TAG_OCTET_STRING) {
    0          
711 0           key->ecdsa.private_value = pdfmake_arena_alloc(arena, priv->length);
712 0 0         if (key->ecdsa.private_value) {
713 0           memcpy(key->ecdsa.private_value, priv->data, priv->length);
714 0           key->ecdsa.private_value_len = priv->length;
715             }
716             }
717            
718             /* Look for public key in [1] */
719 0           child = ec_key->children;
720 0 0         while (child) {
721 0 0         if ((child->tag & ASN1_CLASS_MASK) == ASN1_CLASS_CONTEXT &&
722 0 0         (child->tag & 0x1F) == 1) {
723             /* [1] contains BIT STRING with public point */
724 0           pdfmake_asn1_node_t *pub = child->children;
725 0 0         if (pub && pub->tag == ASN1_TAG_BIT_STRING) {
    0          
726             const uint8_t *bits;
727             size_t bit_count;
728 0 0         if (pdfmake_asn1_get_bit_string(pub, &bits, &bit_count) == 0) {
729 0           key->ecdsa.public_point = pdfmake_arena_alloc(arena, bit_count / 8);
730 0 0         if (key->ecdsa.public_point) {
731 0           memcpy(key->ecdsa.public_point, bits, bit_count / 8);
732 0           key->ecdsa.public_point_len = bit_count / 8;
733             }
734             }
735             }
736 0           break;
737             }
738 0           child = child->next;
739             }
740             }
741             }
742             }
743            
744 1           return key;
745             }
746              
747 0           pdfmake_privkey_t *pdfmake_privkey_parse_pem(
748             pdfmake_arena_t *arena,
749             const char *pem,
750             size_t len,
751             const char *password)
752             {
753             const char *begin;
754             const char *end;
755             const char *content_start;
756             int is_encrypted;
757             size_t b64_len;
758             size_t max_der_len;
759             uint8_t *der;
760             size_t der_len;
761              
762 0 0         if (!arena || !pem || len == 0) return NULL;
    0          
    0          
763            
764             /* Find BEGIN marker */
765 0           begin = strstr(pem, "-----BEGIN");
766 0 0         if (!begin) return NULL;
767            
768             /* Find END marker */
769 0           end = strstr(begin, "-----END");
770 0 0         if (!end) return NULL;
771            
772             /* Skip to content */
773 0           content_start = strchr(begin, '\n');
774 0 0         if (!content_start) return NULL;
775 0           content_start++;
776            
777             /* Check for encryption headers */
778 0           is_encrypted = 0;
779 0 0         if (strstr(begin, "ENCRYPTED") != NULL) {
780 0           is_encrypted = 1;
781             }
782            
783             /* Find end of headers */
784 0 0         while (content_start < end && *content_start != '\n' &&
    0          
785 0 0         (content_start[0] == 'P' || content_start[0] == 'D')) {
    0          
786             /* Skip header lines like "Proc-Type:" and "DEK-Info:" */
787 0           content_start = strchr(content_start, '\n');
788 0 0         if (content_start) content_start++;
789             }
790            
791             /* Skip blank line */
792 0 0         if (content_start && *content_start == '\n') content_start++;
    0          
793            
794             /* Decode base64 */
795 0           b64_len = end - content_start;
796 0           max_der_len = (b64_len * 3) / 4 + 4;
797 0           der = pdfmake_arena_alloc(arena, max_der_len);
798 0 0         if (!der) return NULL;
799            
800 0           der_len = base64_decode(content_start, b64_len, der, max_der_len);
801 0 0         if (der_len == 0) return NULL;
802            
803 0 0         if (is_encrypted && password) {
    0          
804             /* TODO: Implement PKCS#5/PKCS#8 decryption */
805             /* For now, return NULL for encrypted keys */
806 0           return NULL;
807             }
808            
809 0           return pdfmake_pkcs8_parse_der(arena, der, der_len);
810             }
811              
812 0           pdfmake_privkey_t *pdfmake_privkey_load_file(
813             pdfmake_arena_t *arena,
814             const char *path,
815             const char *password)
816             {
817             FILE *f;
818             long size;
819             uint8_t *data;
820              
821 0 0         if (!arena || !path) return NULL;
    0          
822            
823 0           f = fopen(path, "rb");
824 0 0         if (!f) return NULL;
825            
826 0           fseek(f, 0, SEEK_END);
827 0           size = ftell(f);
828 0           fseek(f, 0, SEEK_SET);
829            
830 0 0         if (size <= 0 || size > 1024 * 1024) {
    0          
831 0           fclose(f);
832 0           return NULL;
833             }
834            
835 0           data = pdfmake_arena_alloc(arena, size);
836 0 0         if (!data) {
837 0           fclose(f);
838 0           return NULL;
839             }
840            
841 0 0         if (fread(data, 1, size, f) != (size_t)size) {
842 0           fclose(f);
843 0           return NULL;
844             }
845 0           fclose(f);
846            
847             /* Check for PEM format */
848 0 0         if (size > 10 && memcmp(data, "-----BEGIN", 10) == 0) {
    0          
849 0           return pdfmake_privkey_parse_pem(arena, (const char *)data, size, password);
850             }
851            
852             /* Assume DER */
853 0           return pdfmake_pkcs8_parse_der(arena, data, size);
854             }
855              
856             /*============================================================================
857             * PKCS#12 Parsing (simplified)
858             *==========================================================================*/
859              
860             /*============================================================================
861             * PBE Decryption Helpers
862             *==========================================================================*/
863              
864             /* Decrypt data encrypted with pbeWithSHAAnd3-KeyTripleDES-CBC (OID 1.2.840.113549.1.12.1.3)
865             * AlgorithmIdentifier contains: SEQUENCE { OID, SEQUENCE { salt OCTET STRING, iterations INTEGER } }
866             */
867 2           static uint8_t *pbe_sha1_3des_decrypt(
868             pdfmake_arena_t *arena,
869             const char *password,
870             const pdfmake_asn1_node_t *alg_id,
871             const uint8_t *ciphertext,
872             size_t ct_len,
873             size_t *out_len)
874             {
875             pdfmake_asn1_node_t *params;
876             pdfmake_asn1_node_t *salt_node;
877             pdfmake_asn1_node_t *iter_node;
878             /* Parse algorithm parameters: SEQUENCE { salt OCTET STRING, iterations INTEGER } */
879             int64_t iterations;
880             uint8_t key[24], iv[8];
881             uint8_t *plain;
882             uint8_t pad;
883             size_t i;
884              
885 2           params = pdfmake_asn1_child_at(alg_id, 1);
886 2 50         if (!pdfmake_asn1_is_sequence(params))
887 0           return NULL;
888              
889 2           salt_node = pdfmake_asn1_child_at(params, 0);
890 2           iter_node = pdfmake_asn1_child_at(params, 1);
891 2 50         if (!salt_node || !iter_node) return NULL;
    50          
892              
893 2 50         if (pdfmake_asn1_get_int64(iter_node, &iterations) != 0 || iterations <= 0)
    50          
894 0           return NULL;
895              
896             /* Derive 24-byte key + 8-byte IV using PKCS#12 KDF */
897 2           pkcs12_kdf(password, salt_node->data, salt_node->length,
898             (int)iterations, 1 /* key */, key, 24);
899 2           pkcs12_kdf(password, salt_node->data, salt_node->length,
900             (int)iterations, 2 /* IV */, iv, 8);
901              
902             /* Decrypt */
903 2 50         if (ct_len == 0 || ct_len % 8 != 0) return NULL;
    50          
904              
905 2           plain = pdfmake_arena_alloc(arena, ct_len);
906 2 50         if (!plain) return NULL;
907              
908 2           des3_cbc_decrypt(ciphertext, ct_len, key, iv, plain);
909              
910             /* Remove PKCS#7 padding */
911 2           pad = plain[ct_len - 1];
912 2 50         if (pad == 0 || pad > 8) return NULL;
    50          
913 15 100         for (i = 0; i < pad; i++) {
914 13 50         if (plain[ct_len - 1 - i] != pad) return NULL;
915             }
916 2           *out_len = ct_len - pad;
917 2           return plain;
918             }
919              
920             /* Decrypt data encrypted with PBES2 (PBKDF2 + AES-CBC) */
921 0           static uint8_t *pbes2_decrypt(
922             pdfmake_arena_t *arena,
923             const char *password,
924             const pdfmake_asn1_node_t *alg_id,
925             const uint8_t *ciphertext,
926             size_t ct_len,
927             size_t *out_len)
928             {
929             pdfmake_asn1_node_t *params;
930             pdfmake_asn1_node_t *kdf;
931             pdfmake_asn1_node_t *enc;
932             pdfmake_asn1_node_t *kdf_oid;
933             pdfmake_asn1_node_t *kdf_params;
934             pdfmake_asn1_node_t *salt_node;
935             pdfmake_asn1_node_t *iter_node;
936             int64_t iterations;
937             pdfmake_asn1_node_t *enc_oid;
938             char *enc_oid_str;
939             size_t key_len;
940             pdfmake_asn1_node_t *enc_params;
941             size_t pwd_len;
942             uint8_t dk[32];
943             size_t dk_produced;
944             uint32_t block_num;
945             uint8_t U[20], T[20];
946             uint8_t ipad[64], opad[64];
947             size_t j;
948             uint8_t pwd_hash[20];
949             uint8_t be32[4];
950             sha1_ctx_t ctx;
951             int64_t jj;
952             uint8_t prev[20];
953             int k;
954             size_t to_copy;
955             uint8_t *plain;
956             int plain_len;
957              
958             /* PBES2-params ::= SEQUENCE { keyDerivationFunc AlgorithmIdentifier, encryptionScheme AlgorithmIdentifier } */
959 0           params = pdfmake_asn1_child_at(alg_id, 1);
960 0 0         if (!pdfmake_asn1_is_sequence(params))
961 0           return NULL;
962              
963 0           kdf = pdfmake_asn1_child_at(params, 0);
964 0           enc = pdfmake_asn1_child_at(params, 1);
965 0 0         if (!kdf || !enc) return NULL;
    0          
966 0 0         if (!pdfmake_asn1_is_sequence(kdf)) return NULL;
967 0 0         if (!pdfmake_asn1_is_sequence(enc)) return NULL;
968              
969             /* Check KDF is PBKDF2 */
970 0           kdf_oid = pdfmake_asn1_child_at(kdf, 0);
971 0 0         if (!kdf_oid || !pdfmake_asn1_oid_equals(kdf_oid, OID_PBKDF2))
    0          
972 0           return NULL;
973              
974             /* PBKDF2-params ::= SEQUENCE { salt OCTET STRING, iterationCount INTEGER,
975             keyLength INTEGER OPTIONAL, prf AlgorithmIdentifier DEFAULT hmacWithSHA1 } */
976 0           kdf_params = pdfmake_asn1_child_at(kdf, 1);
977 0 0         if (!kdf_params) return NULL;
978              
979 0           salt_node = pdfmake_asn1_child_at(kdf_params, 0);
980 0           iter_node = pdfmake_asn1_child_at(kdf_params, 1);
981 0 0         if (!salt_node || !iter_node) return NULL;
    0          
982              
983 0 0         if (pdfmake_asn1_get_int64(iter_node, &iterations) != 0) return NULL;
984              
985             /* Determine encryption scheme and key length */
986 0           enc_oid = pdfmake_asn1_child_at(enc, 0);
987 0 0         if (!enc_oid) return NULL;
988              
989 0           enc_oid_str = pdfmake_asn1_get_oid_string(arena, enc_oid);
990 0 0         if (!enc_oid_str) return NULL;
991              
992 0 0         if (strcmp(enc_oid_str, OID_AES256_CBC) == 0) key_len = 32;
993 0 0         else if (strcmp(enc_oid_str, OID_AES192_CBC) == 0) key_len = 24;
994 0 0         else if (strcmp(enc_oid_str, OID_AES128_CBC) == 0) key_len = 16;
995 0           else return NULL; /* unsupported cipher */
996              
997             /* Get IV from encryption scheme params */
998 0           enc_params = pdfmake_asn1_child_at(enc, 1);
999 0 0         if (!enc_params || enc_params->tag != ASN1_TAG_OCTET_STRING || enc_params->length != 16)
    0          
    0          
1000 0           return NULL;
1001              
1002             /* PBKDF2: derive key using HMAC-SHA1 (default PRF)
1003             * For simplicity, use PKCS#12 KDF as a stand-in when PBKDF2 is needed.
1004             * True PBKDF2 = HMAC-SHA256 iterated — implement proper PBKDF2 here. */
1005 0 0         pwd_len = password ? strlen(password) : 0;
1006              
1007             /* PBKDF2 with HMAC-SHA1 */
1008             /* F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc
1009             U1 = PRF(Password, Salt || INT(i)) where PRF = HMAC-SHA1 */
1010             {
1011 0           dk_produced = 0;
1012 0           block_num = 1;
1013 0 0         while (dk_produced < key_len) {
1014             /* U1 = HMAC-SHA1(password, salt || block_num_be32) */
1015             /* Build HMAC-SHA1 key pad */
1016 0           memset(ipad, 0x36, 64);
1017 0           memset(opad, 0x5C, 64);
1018 0 0         for (j = 0; j < pwd_len && j < 64; j++) {
    0          
1019 0           ipad[j] ^= (uint8_t)password[j];
1020 0           opad[j] ^= (uint8_t)password[j];
1021             }
1022 0 0         if (pwd_len > 64) {
1023             /* Hash the password first */
1024 0           sha1((const uint8_t *)password, pwd_len, pwd_hash);
1025 0           memset(ipad, 0x36, 64);
1026 0           memset(opad, 0x5C, 64);
1027 0 0         for (j = 0; j < 20; j++) {
1028 0           ipad[j] ^= pwd_hash[j];
1029 0           opad[j] ^= pwd_hash[j];
1030             }
1031             }
1032              
1033             /* U1 = HMAC(password, salt || be32(block_num)) */
1034 0           be32[0] = (block_num >> 24) & 0xFF;
1035 0           be32[1] = (block_num >> 16) & 0xFF;
1036 0           be32[2] = (block_num >> 8) & 0xFF;
1037 0           be32[3] = block_num & 0xFF;
1038              
1039 0           sha1_init(&ctx);
1040 0           sha1_update(&ctx, ipad, 64);
1041 0           sha1_update(&ctx, salt_node->data, salt_node->length);
1042 0           sha1_update(&ctx, be32, 4);
1043 0           sha1_final(&ctx, U);
1044              
1045 0           sha1_init(&ctx);
1046 0           sha1_update(&ctx, opad, 64);
1047 0           sha1_update(&ctx, U, 20);
1048 0           sha1_final(&ctx, U);
1049              
1050 0           memcpy(T, U, 20);
1051              
1052             /* Subsequent iterations */
1053 0 0         for (jj = 1; jj < iterations; jj++) {
1054 0           memcpy(prev, U, 20);
1055              
1056 0           sha1_init(&ctx);
1057 0           sha1_update(&ctx, ipad, 64);
1058 0           sha1_update(&ctx, prev, 20);
1059 0           sha1_final(&ctx, U);
1060              
1061 0           sha1_init(&ctx);
1062 0           sha1_update(&ctx, opad, 64);
1063 0           sha1_update(&ctx, U, 20);
1064 0           sha1_final(&ctx, U);
1065              
1066 0 0         for (k = 0; k < 20; k++)
1067 0           T[k] ^= U[k];
1068             }
1069              
1070 0           to_copy = key_len - dk_produced;
1071 0 0         if (to_copy > 20) to_copy = 20;
1072 0           memcpy(dk + dk_produced, T, to_copy);
1073 0           dk_produced += to_copy;
1074 0           block_num++;
1075             }
1076             }
1077              
1078             /* AES-CBC decrypt */
1079 0 0         if (ct_len == 0 || ct_len % 16 != 0) return NULL;
    0          
1080              
1081 0           plain = pdfmake_arena_alloc(arena, ct_len);
1082 0 0         if (!plain) return NULL;
1083              
1084 0           plain_len = pdfmake_aes_cbc_decrypt(dk, key_len, enc_params->data,
1085             ciphertext, ct_len, plain);
1086 0 0         if (plain_len < 0) return NULL;
1087              
1088 0           *out_len = (size_t)plain_len;
1089 0           return plain;
1090             }
1091              
1092             /* Decrypt encrypted content using detected algorithm */
1093 2           static uint8_t *pbe_decrypt(
1094             pdfmake_arena_t *arena,
1095             const char *password,
1096             const pdfmake_asn1_node_t *alg_id,
1097             const uint8_t *ciphertext,
1098             size_t ct_len,
1099             size_t *out_len)
1100             {
1101             pdfmake_asn1_node_t *oid_node;
1102             char *oid;
1103              
1104 2           oid_node = pdfmake_asn1_child_at(alg_id, 0);
1105 2 50         if (!oid_node) return NULL;
1106              
1107 2           oid = pdfmake_asn1_get_oid_string(arena, oid_node);
1108 2 50         if (!oid) return NULL;
1109              
1110 2 50         if (strcmp(oid, OID_PBE_SHA1_3DES) == 0 ||
1111 0 0         strcmp(oid, OID_PBE_SHA1_2DES) == 0) {
1112 2           return pbe_sha1_3des_decrypt(arena, password, alg_id,
1113             ciphertext, ct_len, out_len);
1114 0 0         } else if (strcmp(oid, OID_PBES2) == 0) {
1115 0           return pbes2_decrypt(arena, password, alg_id,
1116             ciphertext, ct_len, out_len);
1117             }
1118              
1119 0           return NULL; /* unsupported PBE algorithm */
1120             }
1121              
1122             /*============================================================================
1123             * SafeBag Processing
1124             *==========================================================================*/
1125              
1126             /* Process a single SafeBag and populate identity fields */
1127 2           static void process_safe_bag(
1128             pdfmake_arena_t *arena,
1129             const char *password,
1130             pdfmake_asn1_node_t *bag,
1131             pdfmake_signing_identity_t *identity)
1132             {
1133             pdfmake_asn1_node_t *bag_oid;
1134             pdfmake_asn1_node_t *bag_value_wrapper;
1135             char *oid;
1136             pdfmake_asn1_node_t *bag_value;
1137             pdfmake_asn1_node_t *enc_alg;
1138             pdfmake_asn1_node_t *enc_data;
1139             size_t plain_len;
1140             uint8_t *plain;
1141             pdfmake_asn1_node_t *cert_id;
1142             pdfmake_asn1_node_t *cert_val_wrapper;
1143             pdfmake_asn1_node_t *cert_octet;
1144              
1145             /* SafeBag ::= SEQUENCE { bagId OID, bagValue [0] EXPLICIT ANY, bagAttributes SET OF OPTIONAL } */
1146 2 50         if (!pdfmake_asn1_is_sequence(bag)) return;
1147              
1148 2           bag_oid = pdfmake_asn1_child_at(bag, 0);
1149 2           bag_value_wrapper = pdfmake_asn1_child_at(bag, 1);
1150 2 50         if (!bag_oid || !bag_value_wrapper) return;
    50          
1151              
1152 2           oid = pdfmake_asn1_get_oid_string(arena, bag_oid);
1153 2 50         if (!oid) return;
1154              
1155             /* The [0] EXPLICIT wrapper: get inner content */
1156 2           bag_value = bag_value_wrapper->children;
1157 2 50         if (!bag_value) return;
1158              
1159 2 100         if (strcmp(oid, OID_PKCS12_SHROUDEDKEYBAG) == 0 && !identity->privkey) {
    50          
1160             /* PKCS8ShroudedKeyBag — EncryptedPrivateKeyInfo ::= SEQUENCE {
1161             encryptionAlgorithm AlgorithmIdentifier,
1162             encryptedData OCTET STRING } */
1163 1 50         if (!pdfmake_asn1_is_sequence(bag_value)) return;
1164              
1165 1           enc_alg = pdfmake_asn1_child_at(bag_value, 0);
1166 1           enc_data = pdfmake_asn1_child_at(bag_value, 1);
1167 1 50         if (!enc_alg || !enc_data) return;
    50          
1168 1 50         if (enc_data->tag != ASN1_TAG_OCTET_STRING) return;
1169              
1170 1           plain_len = 0;
1171 1           plain = pbe_decrypt(arena, password, enc_alg,
1172             enc_data->data, enc_data->length, &plain_len);
1173 1 50         if (plain && plain_len > 0) {
    50          
1174 1           identity->privkey = pdfmake_pkcs8_parse_der(arena, plain, plain_len);
1175             }
1176             }
1177 1 50         else if (strcmp(oid, OID_PKCS12_KEYBAG) == 0 && !identity->privkey) {
    0          
1178             /* Unencrypted PKCS#8 PrivateKeyInfo */
1179 0 0         if (pdfmake_asn1_is_sequence(bag_value)) {
1180 0           identity->privkey = pdfmake_pkcs8_parse_der(arena,
1181 0           bag_value->data - 4, /* approx: include tag+len */
1182 0           bag_value->length + 4);
1183             /* Better: re-serialize from raw data range */
1184             /* The bag_value node's data points to the content, but we need full DER.
1185             Use the original data pointer range from bag_value_wrapper. */
1186 0           identity->privkey = pdfmake_pkcs8_parse_der(arena,
1187             bag_value->data,
1188             bag_value->length);
1189             }
1190             }
1191 1 50         else if (strcmp(oid, OID_PKCS12_CERTBAG) == 0 && !identity->cert) {
    50          
1192             /* CertBag ::= SEQUENCE { certId OID, certValue [0] EXPLICIT ANY } */
1193 1 50         if (!pdfmake_asn1_is_sequence(bag_value)) return;
1194              
1195 1           cert_id = pdfmake_asn1_child_at(bag_value, 0);
1196 1           cert_val_wrapper = pdfmake_asn1_child_at(bag_value, 1);
1197 1 50         if (!cert_id || !cert_val_wrapper) return;
    50          
1198              
1199             /* Check it's an X.509 certificate */
1200 1 50         if (!pdfmake_asn1_oid_equals(cert_id, OID_CERT_X509)) return;
1201              
1202             /* The [0] wrapper contains an OCTET STRING with DER-encoded cert */
1203 1           cert_octet = cert_val_wrapper->children;
1204 1 50         if (!cert_octet || cert_octet->tag != ASN1_TAG_OCTET_STRING) return;
    50          
1205              
1206 1           identity->cert = pdfmake_x509_parse_der(arena,
1207             cert_octet->data,
1208             cert_octet->length);
1209             }
1210             }
1211              
1212             /* Process SafeContents (SEQUENCE OF SafeBag) from decrypted data */
1213 2           static void process_safe_contents(
1214             pdfmake_arena_t *arena,
1215             const char *password,
1216             const uint8_t *data,
1217             size_t len,
1218             pdfmake_signing_identity_t *identity)
1219             {
1220 2           size_t pos = 0;
1221 2           pdfmake_asn1_node_t *safe_contents = pdfmake_asn1_parse_element(
1222             arena, data, len, &pos);
1223             pdfmake_asn1_node_t *bag;
1224              
1225 2 50         if (!pdfmake_asn1_is_sequence(safe_contents))
1226 0           return;
1227              
1228             /* Iterate SafeBag items */
1229 4 100         for (bag = safe_contents->children; bag; bag = bag->next) {
1230 2           process_safe_bag(arena, password, bag, identity);
1231             }
1232             }
1233              
1234             /*============================================================================
1235             * Main PKCS#12 Parser
1236             *==========================================================================*/
1237              
1238 1           pdfmake_signing_identity_t *pdfmake_pkcs12_parse(
1239             pdfmake_arena_t *arena,
1240             const uint8_t *data,
1241             size_t len,
1242             const char *password)
1243             {
1244             pdfmake_asn1_node_t *pfx;
1245             pdfmake_asn1_node_t *version;
1246             pdfmake_asn1_node_t *auth_safe;
1247             int64_t ver;
1248             pdfmake_asn1_node_t *content_type;
1249             pdfmake_asn1_node_t *content;
1250             pdfmake_asn1_node_t *octet_string;
1251             size_t pos;
1252             pdfmake_asn1_node_t *auth_safe_seq;
1253             pdfmake_signing_identity_t *identity;
1254             pdfmake_asn1_node_t *ci;
1255             pdfmake_asn1_node_t *ci_type;
1256             pdfmake_asn1_node_t *ci_content;
1257             char *ci_oid;
1258             pdfmake_asn1_node_t *os;
1259             pdfmake_asn1_node_t *ed;
1260             pdfmake_asn1_node_t *ed_version;
1261             pdfmake_asn1_node_t *eci;
1262             pdfmake_asn1_node_t *eci_type;
1263             pdfmake_asn1_node_t *eci_alg;
1264             pdfmake_asn1_node_t *eci_data;
1265             size_t plain_len;
1266             uint8_t *plain;
1267              
1268 1 50         if (!arena || !data || len == 0) return NULL;
    50          
    50          
1269              
1270             /* Parse PFX structure */
1271             /* PFX ::= SEQUENCE {
1272             version INTEGER,
1273             authSafe ContentInfo,
1274             macData MacData OPTIONAL } */
1275              
1276 1           pfx = pdfmake_asn1_parse(arena, data, len);
1277 1 50         if (!pdfmake_asn1_is_sequence(pfx))
1278 0           return NULL;
1279              
1280 1           version = pdfmake_asn1_child_at(pfx, 0);
1281 1           auth_safe = pdfmake_asn1_child_at(pfx, 1);
1282 1 50         if (!version || !auth_safe) return NULL;
    50          
1283              
1284 1 50         if (pdfmake_asn1_get_int64(version, &ver) != 0 || ver != 3)
    50          
1285 0           return NULL;
1286              
1287             /* Parse outer ContentInfo: must be pkcs7-data */
1288 1 50         if (!pdfmake_asn1_is_sequence(auth_safe))
1289 0           return NULL;
1290              
1291 1           content_type = pdfmake_asn1_child_at(auth_safe, 0);
1292 1           content = pdfmake_asn1_child_at(auth_safe, 1);
1293 1 50         if (!content_type || !content) return NULL;
    50          
1294              
1295 1 50         if (!pdfmake_asn1_oid_equals(content_type, OID_PKCS7_DATA))
1296 0           return NULL;
1297              
1298             /* The [0] wrapper contains OCTET STRING */
1299 1           octet_string = content->children;
1300 1 50         if (!octet_string || octet_string->tag != ASN1_TAG_OCTET_STRING)
    50          
1301 0           return NULL;
1302              
1303             /* Parse AuthenticatedSafe (SEQUENCE OF ContentInfo) */
1304 1           pos = 0;
1305 1           auth_safe_seq = pdfmake_asn1_parse_element(
1306             arena, octet_string->data, octet_string->length, &pos);
1307              
1308 1 50         if (!pdfmake_asn1_is_sequence(auth_safe_seq))
1309 0           return NULL;
1310              
1311             /* Create identity to populate */
1312 1           identity = pdfmake_arena_alloc(
1313             arena, sizeof(pdfmake_signing_identity_t));
1314 1 50         if (!identity) return NULL;
1315 1           memset(identity, 0, sizeof(pdfmake_signing_identity_t));
1316 1           identity->arena = arena;
1317              
1318             /* Process each ContentInfo in the AuthenticatedSafe */
1319 3 100         for (ci = auth_safe_seq->children; ci; ci = ci->next) {
1320 2 50         if (!pdfmake_asn1_is_sequence(ci)) continue;
1321              
1322 2           ci_type = pdfmake_asn1_child_at(ci, 0);
1323 2           ci_content = pdfmake_asn1_child_at(ci, 1);
1324 2 50         if (!ci_type || !ci_content) continue;
    50          
1325              
1326 2           ci_oid = pdfmake_asn1_get_oid_string(arena, ci_type);
1327 2 50         if (!ci_oid) continue;
1328              
1329 2 100         if (strcmp(ci_oid, OID_PKCS7_DATA) == 0) {
1330             /* Unencrypted SafeContents — wrapped in [0] EXPLICIT { OCTET STRING } */
1331 1           os = ci_content->children;
1332 1 50         if (!os || os->tag != ASN1_TAG_OCTET_STRING) continue;
    50          
1333              
1334 1           process_safe_contents(arena, password,
1335             os->data, os->length, identity);
1336             }
1337 1 50         else if (strcmp(ci_oid, OID_PKCS7_ENCRYPTED) == 0) {
1338             /* EncryptedData ContentInfo:
1339             [0] EXPLICIT { EncryptedData ::= SEQUENCE {
1340             version INTEGER,
1341             encryptedContentInfo EncryptedContentInfo } }
1342             EncryptedContentInfo ::= SEQUENCE {
1343             contentType OID,
1344             contentEncryptionAlgorithm AlgorithmIdentifier,
1345             encryptedContent [0] IMPLICIT OCTET STRING } */
1346 1           ed = ci_content->children;
1347 1 50         if (!pdfmake_asn1_is_sequence(ed))
1348 0           continue;
1349              
1350 1           ed_version = pdfmake_asn1_child_at(ed, 0);
1351 1           eci = pdfmake_asn1_child_at(ed, 1);
1352             (void)ed_version;
1353 1 50         if (!pdfmake_asn1_is_sequence(eci))
1354 0           continue;
1355              
1356 1           eci_type = pdfmake_asn1_child_at(eci, 0);
1357 1           eci_alg = pdfmake_asn1_child_at(eci, 1);
1358 1           eci_data = pdfmake_asn1_child_at(eci, 2);
1359             (void)eci_type;
1360 1 50         if (!eci_alg || !eci_data) continue;
    50          
1361              
1362             /* eci_data is [0] IMPLICIT OCTET STRING (tag 0x80 or 0xA0) */
1363             /* Its data/length contain the ciphertext */
1364 1           plain_len = 0;
1365 1           plain = pbe_decrypt(arena, password, eci_alg,
1366             eci_data->data, eci_data->length,
1367             &plain_len);
1368 1 50         if (plain && plain_len > 0) {
    50          
1369 1           process_safe_contents(arena, password,
1370             plain, plain_len, identity);
1371             }
1372             }
1373             }
1374              
1375             /* Return identity only if we got at least a key or cert */
1376 1 50         if (!identity->privkey && !identity->cert)
    0          
1377 0           return NULL;
1378              
1379 1           return identity;
1380             }
1381              
1382 0           pdfmake_signing_identity_t *pdfmake_pkcs12_load_file(
1383             pdfmake_arena_t *arena,
1384             const char *path,
1385             const char *password)
1386             {
1387             FILE *f;
1388             long size;
1389             uint8_t *data;
1390              
1391 0 0         if (!arena || !path) return NULL;
    0          
1392            
1393 0           f = fopen(path, "rb");
1394 0 0         if (!f) return NULL;
1395            
1396 0           fseek(f, 0, SEEK_END);
1397 0           size = ftell(f);
1398 0           fseek(f, 0, SEEK_SET);
1399            
1400 0 0         if (size <= 0 || size > 10 * 1024 * 1024) { /* Max 10MB */
    0          
1401 0           fclose(f);
1402 0           return NULL;
1403             }
1404            
1405 0           data = pdfmake_arena_alloc(arena, size);
1406 0 0         if (!data) {
1407 0           fclose(f);
1408 0           return NULL;
1409             }
1410            
1411 0 0         if (fread(data, 1, size, f) != (size_t)size) {
1412 0           fclose(f);
1413 0           return NULL;
1414             }
1415 0           fclose(f);
1416            
1417 0           return pdfmake_pkcs12_parse(arena, data, size, password);
1418             }
1419              
1420 0           pdfmake_signing_identity_t *pdfmake_signing_identity_create(
1421             pdfmake_arena_t *arena,
1422             pdfmake_privkey_t *key,
1423             pdfmake_x509_cert_t *cert,
1424             pdfmake_cert_chain_t *chain)
1425             {
1426             pdfmake_signing_identity_t *identity;
1427              
1428 0 0         if (!arena || !key || !cert) return NULL;
    0          
    0          
1429            
1430 0           identity = pdfmake_arena_alloc(arena, sizeof(pdfmake_signing_identity_t));
1431 0 0         if (!identity) return NULL;
1432            
1433 0           identity->arena = arena;
1434 0           identity->privkey = key;
1435 0           identity->cert = cert;
1436 0           identity->chain = chain;
1437            
1438 0           return identity;
1439             }
1440              
1441 0           int pdfmake_privkey_bits(const pdfmake_privkey_t *key)
1442             {
1443 0 0         if (!key) return 0;
1444            
1445 0           switch (key->algorithm) {
1446 0           case PDFMAKE_PK_RSA:
1447             /* RSA key size is modulus size in bits */
1448 0 0         if (key->rsa.modulus && key->rsa.modulus_len > 0) {
    0          
1449             /* Skip leading zero byte if present */
1450 0           size_t len = key->rsa.modulus_len;
1451 0           const uint8_t *mod = key->rsa.modulus;
1452 0 0         if (len > 0 && mod[0] == 0) {
    0          
1453 0           mod++;
1454 0           len--;
1455             }
1456 0           return len * 8;
1457             }
1458 0           break;
1459            
1460 0           case PDFMAKE_PK_ECDSA:
1461 0           return key->ecdsa.curve_bits;
1462            
1463 0           default:
1464 0           break;
1465             }
1466            
1467 0           return 0;
1468             }
1469              
1470 0           int pdfmake_privkey_matches_cert(
1471             const pdfmake_privkey_t *key,
1472             const pdfmake_x509_cert_t *cert)
1473             {
1474 0 0         if (!key || !cert) return 0;
    0          
1475            
1476             /* Check algorithm match */
1477 0 0         if (key->algorithm != cert->pubkey.algorithm) return 0;
1478            
1479 0           switch (key->algorithm) {
1480 0           case PDFMAKE_PK_RSA:
1481             /* Compare modulus */
1482 0 0         if (key->rsa.modulus_len != cert->pubkey.rsa.modulus_len) return 0;
1483 0           if (memcmp(key->rsa.modulus, cert->pubkey.rsa.modulus,
1484 0 0         key->rsa.modulus_len) != 0) return 0;
1485 0           return 1;
1486            
1487 0           case PDFMAKE_PK_ECDSA:
1488             /* Compare curve and public point */
1489 0 0         if (key->ecdsa.curve_bits != cert->pubkey.ecdsa.curve_bits) return 0;
1490             /* Would need to derive public point from private key to fully verify */
1491 0           return 1;
1492            
1493 0           default:
1494 0           break;
1495             }
1496            
1497 0           return 0;
1498             }
1499              
1500 1           void pdfmake_privkey_free(pdfmake_privkey_t *key)
1501             {
1502 1 50         if (!key) return;
1503            
1504             /* Securely wipe sensitive data */
1505 1 50         if (key->algorithm == PDFMAKE_PK_RSA) {
1506 1 50         if (key->rsa.private_exponent) {
1507 1           memset(key->rsa.private_exponent, 0, key->rsa.private_exponent_len);
1508             }
1509 1 50         if (key->rsa.prime1) {
1510 1           memset(key->rsa.prime1, 0, key->rsa.prime1_len);
1511             }
1512 1 50         if (key->rsa.prime2) {
1513 1           memset(key->rsa.prime2, 0, key->rsa.prime2_len);
1514             }
1515 0 0         } else if (key->algorithm == PDFMAKE_PK_ECDSA) {
1516 0 0         if (key->ecdsa.private_value) {
1517 0           memset(key->ecdsa.private_value, 0, key->ecdsa.private_value_len);
1518             }
1519             }
1520            
1521 1 50         if (key->pkcs8_der) {
1522 1           memset(key->pkcs8_der, 0, key->pkcs8_der_len);
1523             }
1524            
1525             /* If from arena, arena cleanup handles deallocation */
1526             }
1527              
1528 1           void pdfmake_signing_identity_free(pdfmake_signing_identity_t *id)
1529             {
1530 1 50         if (!id) return;
1531            
1532 1 50         if (id->privkey) {
1533 1           pdfmake_privkey_free(id->privkey);
1534             }
1535            
1536             /* If from arena, arena cleanup handles deallocation */
1537             }