1 /* $NetBSD: file.c,v 1.3 2023/06/19 21:41:44 christos Exp $ */
2
3 /*
4 * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "hx_locl.h"
37
38 int
_hx509_map_file_os(const char * fn,heim_octet_string * os)39 _hx509_map_file_os(const char *fn, heim_octet_string *os)
40 {
41 size_t length;
42 void *data;
43 int ret;
44
45 ret = rk_undumpdata(fn, &data, &length);
46
47 os->data = data;
48 os->length = length;
49
50 return ret;
51 }
52
53 void
_hx509_unmap_file_os(heim_octet_string * os)54 _hx509_unmap_file_os(heim_octet_string *os)
55 {
56 rk_xfree(os->data);
57 }
58
59 int
_hx509_write_file(const char * fn,const void * data,size_t length)60 _hx509_write_file(const char *fn, const void *data, size_t length)
61 {
62 rk_dumpdata(fn, data, length);
63 return 0;
64 }
65
66 /*
67 *
68 */
69
70 static void
print_pem_stamp(FILE * f,const char * type,const char * str)71 print_pem_stamp(FILE *f, const char *type, const char *str)
72 {
73 fprintf(f, "-----%s %s-----\n", type, str);
74 }
75
76 int
hx509_pem_write(hx509_context context,const char * type,hx509_pem_header * headers,FILE * f,const void * data,size_t size)77 hx509_pem_write(hx509_context context, const char *type,
78 hx509_pem_header *headers, FILE *f,
79 const void *data, size_t size)
80 {
81 const char *p = data;
82 size_t length;
83 char *line;
84
85 #define ENCODE_LINE_LENGTH 54
86
87 print_pem_stamp(f, "BEGIN", type);
88
89 while (headers) {
90 fprintf(f, "%s: %s\n%s",
91 headers->header, headers->value,
92 headers->next ? "" : "\n");
93 headers = headers->next;
94 }
95
96 while (size > 0) {
97 ssize_t l;
98
99 length = size;
100 if (length > ENCODE_LINE_LENGTH)
101 length = ENCODE_LINE_LENGTH;
102
103 l = rk_base64_encode(p, length, &line);
104 if (l < 0) {
105 hx509_set_error_string(context, 0, ENOMEM,
106 "malloc - out of memory");
107 return ENOMEM;
108 }
109 size -= length;
110 fprintf(f, "%s\n", line);
111 p += length;
112 free(line);
113 }
114
115 print_pem_stamp(f, "END", type);
116
117 return 0;
118 }
119
120 /*
121 *
122 */
123
124 int
hx509_pem_add_header(hx509_pem_header ** headers,const char * header,const char * value)125 hx509_pem_add_header(hx509_pem_header **headers,
126 const char *header, const char *value)
127 {
128 hx509_pem_header *h;
129
130 h = calloc(1, sizeof(*h));
131 if (h == NULL)
132 return ENOMEM;
133 h->header = strdup(header);
134 if (h->header == NULL) {
135 free(h);
136 return ENOMEM;
137 }
138 h->value = strdup(value);
139 if (h->value == NULL) {
140 free(h->header);
141 free(h);
142 return ENOMEM;
143 }
144
145 h->next = *headers;
146 *headers = h;
147
148 return 0;
149 }
150
151 void
hx509_pem_free_header(hx509_pem_header * headers)152 hx509_pem_free_header(hx509_pem_header *headers)
153 {
154 hx509_pem_header *h;
155 while (headers) {
156 h = headers;
157 headers = headers->next;
158 free(h->header);
159 free(h->value);
160 free(h);
161 }
162 }
163
164 /*
165 *
166 */
167
168 const char *
hx509_pem_find_header(const hx509_pem_header * h,const char * header)169 hx509_pem_find_header(const hx509_pem_header *h, const char *header)
170 {
171 while(h) {
172 if (strcmp(header, h->header) == 0)
173 return h->value;
174 h = h->next;
175 }
176 return NULL;
177 }
178
179
180 /*
181 *
182 */
183
184 int
hx509_pem_read(hx509_context context,FILE * f,hx509_pem_read_func func,void * ctx)185 hx509_pem_read(hx509_context context,
186 FILE *f,
187 hx509_pem_read_func func,
188 void *ctx)
189 {
190 hx509_pem_header *headers = NULL;
191 char *type = NULL;
192 void *data = NULL;
193 size_t len = 0;
194 char buf[1024];
195 int ret = HX509_PARSING_KEY_FAILED;
196
197 enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where;
198
199 where = BEFORE;
200
201 while (fgets(buf, sizeof(buf), f) != NULL) {
202 char *p;
203 int i;
204
205 i = strcspn(buf, "\n");
206 if (buf[i] == '\n') {
207 buf[i] = '\0';
208 if (i > 0)
209 i--;
210 }
211 if (buf[i] == '\r') {
212 buf[i] = '\0';
213 if (i > 0)
214 i--;
215 }
216
217 switch (where) {
218 case BEFORE:
219 if (strncmp("-----BEGIN ", buf, 11) == 0) {
220 type = strdup(buf + 11);
221 if (type == NULL)
222 break;
223 p = strchr(type, '-');
224 if (p)
225 *p = '\0';
226 where = SEARCHHEADER;
227 }
228 break;
229 case SEARCHHEADER:
230 p = strchr(buf, ':');
231 if (p == NULL) {
232 where = INDATA;
233 goto indata;
234 }
235 /* FALLTHROUGH */
236 case INHEADER:
237 if (buf[0] == '\0') {
238 where = INDATA;
239 break;
240 }
241 p = strchr(buf, ':');
242 if (p) {
243 *p++ = '\0';
244 while (isspace((int)*p))
245 p++;
246 ret = hx509_pem_add_header(&headers, buf, p);
247 if (ret)
248 abort();
249 }
250 break;
251 case INDATA:
252 indata:
253
254 if (strncmp("-----END ", buf, 9) == 0) {
255 where = DONE;
256 break;
257 }
258
259 p = emalloc(i);
260 i = rk_base64_decode(buf, p);
261 if (i < 0) {
262 free(p);
263 goto out;
264 }
265
266 data = erealloc(data, len + i);
267 memcpy(((char *)data) + len, p, i);
268 free(p);
269 len += i;
270 break;
271 case DONE:
272 abort();
273 }
274
275 if (where == DONE) {
276 ret = (*func)(context, type, headers, data, len, ctx);
277 out:
278 free(data);
279 data = NULL;
280 len = 0;
281 free(type);
282 type = NULL;
283 where = BEFORE;
284 hx509_pem_free_header(headers);
285 headers = NULL;
286 if (ret)
287 break;
288 }
289 }
290
291 if (where != BEFORE) {
292 hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
293 "File ends before end of PEM end tag");
294 ret = HX509_PARSING_KEY_FAILED;
295 }
296 if (data)
297 free(data);
298 if (type)
299 free(type);
300 if (headers)
301 hx509_pem_free_header(headers);
302
303 return ret;
304 }
305