1 /*	$NetBSD: file.c,v 1.1.1.1 2011/04/13 18:15:11 elric 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
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
54 _hx509_unmap_file_os(heim_octet_string *os)
55 {
56     rk_xfree(os->data);
57 }
58 
59 int
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
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
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 = 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
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
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 *
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
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 	    /* FALLTHOUGH */
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 = 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