]> pd.if.org Git - zpackage/blob - crypto/pem.c
add options for fetchurl
[zpackage] / crypto / pem.c
1 #define _POSIX_C_SOURCE 200809L
2
3 #include <stdio.h>
4 #include <unistd.h>
5
6 #include "tlse.h"
7
8 struct pem_loc {
9         size_t start;
10         size_t len;
11         size_t end;
12 };
13
14 #if 0
15 static const unsigned char *find_mem(const char *needle, size_t nlen,
16                 const unsigned char *haystack, size_t hlen,
17                 size_t *offset) {
18         size_t i;
19         const unsigned char *res = 0;
20
21         /* can't be found if it's longer */
22         if (nlen > hlen) {
23                 return NULL;
24         }
25
26         /* empty string at beginning */
27         if (nlen == 0) {
28                 *offset = 0;
29                 return haystack;
30         }
31
32         for (i=0; i<hlen; i++) {
33                 if (nlen + i > hlen) {
34                         /* can't match any more */
35                         break;
36                 }
37                 /* check for first byte */
38                 if (needle[0] == haystack[i]) {
39                         if (memcmp(needle, haystack+i, nlen) == 0) {
40                                 res = haystack+i;
41                                 if (offset) {
42                                         *offset = i;
43                                 }
44                                 break;
45                         }
46                 }
47         }
48         return res;
49 }
50 #endif
51
52 #if 0
53 /* fills in a struct pem_loc with offsets from in to the start
54  * of a pem, and one past the end, and the length of the pem data
55  */
56 static const unsigned char *next_pem(const unsigned char *in, size_t len, struct pem_loc *pem) {
57         size_t i;
58         const unsigned char *next;
59
60         next = find_mem("BEGIN CERT", 10, in, len, &i);
61         if (!next) {
62                 return NULL;
63         }
64
65         while (i<len && in[i] != '\n') {
66                 i++;
67         }
68         if (i >= len) {
69                 return NULL;
70         }
71         i++;
72         pem->start = i;
73
74         /* look for terminating line */
75         next = find_mem("END CERT", 8, in+pem->start, len, &i);
76         if (!next) {
77                 return NULL;
78         }
79         i += pem->start;
80         pem->end = i;
81
82         /* find prev newline */
83         while (in[i] != '\n') {
84                 i--;
85         }
86         pem->len = i - pem->start;
87         i += pem->start;
88
89         /* skip over the terminating line */
90         while (pem->end < len && in[pem->end] != '\n') {
91                 pem->end++;
92         }
93 #if 0
94         fprintf(stderr, "found cert:\n");
95         write(2, in+pem->start, pem->len);
96         write(2, in+pem->start+pem->len, pem->end-pem->start-pem->len+1);
97 #endif
98
99         return in + pem->start;
100 }
101 #endif
102
103 unsigned char *uudecode(const unsigned char *in, size_t len, size_t *outlen) {
104         size_t need = len/4 * 3 + 1;
105         unsigned char *out;
106
107         out = malloc(need);
108         if (out) {
109                 base64decode((const char *)in, len, out, &need);
110                 if (outlen) {
111                         *outlen = need;
112                 }
113         }
114         return out;
115 }
116
117 unsigned char *tls_pem_decode(const unsigned char *data_in,
118                               unsigned int input_length, int cert_index,
119                               unsigned int *output_len) {
120         unsigned int i;
121         size_t alloc_len = input_length / 4 * 3;
122         unsigned char *output = malloc(alloc_len);
123         *output_len = 0;
124         if (!output)
125                 return NULL;
126         unsigned int start_at = 0;
127         unsigned int idx = 0;
128
129         for (i = 0; i < input_length; i++) {
130                 if ((data_in[i] == '\n') || (data_in[i] == '\r'))
131                         continue;
132
133                 if (data_in[i] != '-') {
134                         /* read entire line */
135                         while ((i < input_length) && (data_in[i] != '\n'))
136                                 i++;
137                         continue;
138                 }
139
140                 if (data_in[i] == '-') {
141                         unsigned int end_idx = i;
142                         /* read until end of line */
143                         while ((i < input_length) && (data_in[i] != '\n'))
144                                 i++;
145                         if (start_at) {
146                                 if (cert_index > 0) {
147                                         cert_index--;
148                                         start_at = 0;
149                                 } else {
150                                             base64decode((const char
151                                                                  *)
152                                                                 &data_in
153                                                                 [start_at],
154                                                                 end_idx -
155                                                                 start_at,
156                                                                 output,
157                                                                 &alloc_len);
158                                             idx = alloc_len;
159                                         break;
160                                 }
161                         } else
162                                 start_at = i + 1;
163                 }
164         }
165         *output_len = idx;
166         if (!idx) {
167                 free(output);
168                 return NULL;
169         }
170         return output;
171 }
172
173 #if 0
174 int load_cert_list(struct TLSContext *tls, const unsigned char *buf, size_t
175                 bufsize, struct TLSCertificate **certs, int flags) {
176         struct pem_loc loc = { 0 };
177         struct TLSCertificate *cert = 0;
178         const unsigned char *pem = buf;
179         int count = 0;
180
181         while (bufsize > 0) {
182                 if (bufsize <= loc.end) {
183                         break;
184                 }
185                 bufsize -= loc.end;
186
187                 //fprintf(stderr, "checking %zu bytes at %p\n", remaining, pem);
188                 pem = next_pem(pem, bufsize, &loc);
189                 if (!pem) {
190                         break;
191                 }
192                 cert = asn1_parse(tls, buf+loc.start, loc.len, 0);
193                 if (!cert) {
194                         continue;
195                 }
196 #ifdef TLS_X509_V1_SUPPORT
197                 if (cert->version != 2 && cert->version != 0)
198 #else
199                 if (cert->version != 2)
200 #endif
201                 {
202                         free(cert);
203                         cert = 0;
204                 }
205                 count++;
206
207                 //fprintf(stderr, "found length %zu pem starting at %zu taking %zu bytes\n",
208                                 //loc.len,
209                                 //loc.start,
210                                 //loc.end);
211         }
212         return 0;
213 }
214 #endif
215
216 int add_to_list(struct TLSCertificate ***list, int *len,
217                 struct TLSCertificate *cert) {
218         void *new;
219
220         new = TLS_REALLOC(*list, (*len+1) * sizeof *list);
221         if (new) {
222                 *list = new;
223                 (*list)[(*len)++] = cert;
224         } else {
225                 return 0;
226         }
227         return *len;
228 }
229
230 int tls_load_certificates(struct TLSContext *tls,
231                           const unsigned char *pem, int size) {
232         if (!tls)
233                 return TLS_GENERIC_ERROR;
234
235         unsigned int len;
236         int idx = 0;
237         do {
238                 unsigned char *data =
239                     tls_pem_decode(pem, size, idx++, &len);
240                 if ((!data) || (!len))
241                         break;
242                 struct TLSCertificate *cert =
243                     asn1_parse(tls, data, len, 0);
244                 if (cert) {
245                         if ((cert->version == 2)
246 #ifdef TLS_X509_V1_SUPPORT
247                             || (cert->version == 0)
248 #endif
249                             ) {
250
251                                 free(cert->der_bytes);
252                                 cert->der_bytes = data;
253                                 cert->der_len = len;
254                                 data = NULL;
255                                 if (cert->priv) {
256                                         DEBUG_PRINT
257                                             ("WARNING - parse error (private key encountered in certificate)\n");
258                                         free(cert->priv);
259                                         cert->priv = NULL;
260                                         cert->priv_len = 0;
261                                 }
262                                 add_to_list(&tls->certificates, &tls->certificates_count, cert);
263
264                         } else {
265                                 DEBUG_PRINT
266                                     ("WARNING - certificate version error (v%d)\n",
267                                      (int) cert->version);
268                                 tls_destroy_certificate(cert);
269                         }
270                 }
271                 free(data);
272         } while (1);
273         return tls->certificates_count;
274 }
275
276 int tls_load_private_key(struct TLSContext *tls,
277                          const unsigned char *pem_buffer, int pem_size) {
278         if (!tls)
279                 return TLS_GENERIC_ERROR;
280
281         unsigned int len;
282         int idx = 0;
283         do {
284                 unsigned char *data =
285                     tls_pem_decode(pem_buffer, pem_size, idx++, &len);
286                 if ((!data) || (!len))
287                         break;
288                 struct TLSCertificate *cert =
289                     asn1_parse(tls, data, len, -1);
290                 if (cert) {
291                         if (!cert->der_len) {
292                                 free(cert->der_bytes);
293                                 cert->der_bytes = data;
294                                 cert->der_len = len;
295                         } else {
296                                 free(data);
297                         }
298                         if ((cert) && (cert->priv) && (cert->priv_len)) {
299 #ifdef TLS_ECDSA_SUPPORTED
300                                 if (cert->ec_algorithm) {
301                                         DEBUG_PRINT
302                                             ("Loaded ECC private key\n");
303                                         if (tls->ec_private_key)
304                                                 tls_destroy_certificate
305                                                     (tls->ec_private_key);
306                                         tls->ec_private_key = cert;
307                                         return 1;
308                                 } else
309 #endif
310                                 {
311                                         DEBUG_PRINT
312                                             ("Loaded private key\n");
313                                         if (tls->private_key)
314                                                 tls_destroy_certificate
315                                                     (tls->private_key);
316                                         tls->private_key = cert;
317                                         return 1;
318                                 }
319                         }
320                         tls_destroy_certificate(cert);
321                 } else
322                         free(data);
323         } while (1);
324         return 0;
325 }
326
327 int tls_load_root_certificates(struct TLSContext *tls,
328                                const unsigned char *pem_buffer,
329                                int pem_size) {
330         if (!tls)
331                 return -1;
332
333         unsigned int len;
334         int idx = 0;
335
336         do {
337                 unsigned char *data =
338                     tls_pem_decode(pem_buffer, pem_size, idx++, &len);
339                 if (!data || !len) {
340                         break;
341                 }
342                 struct TLSCertificate *cert = asn1_parse(NULL, data, len, 0);
343                 if (cert) {
344                         if (cert->version == 2) {
345                                 if (cert->priv) {
346                                         DEBUG_PRINT
347                                             ("WARNING - parse error (private key encountered in certificate)\n");
348                                         free(cert->priv);
349                                         cert->priv = NULL;
350                                         cert->priv_len = 0;
351                                 }
352                                 add_to_list(&tls->root_certificates,
353                                                 &tls->root_count,
354                                                 cert);
355                                 DEBUG_PRINT("Loaded certificate: %d\n",
356                                             tls->root_count);
357                         } else {
358                                 DEBUG_PRINT
359                                     ("WARNING - certificate version error (v%d)\n",
360                                      (int) cert->version);
361                                 tls_destroy_certificate(cert);
362                         }
363                 }
364                 free(data);
365         } while (1);
366         return tls->root_count;
367 }
368