| 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
|
|
|
|
|
|
|
} |