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
38int
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
53void
54_hx509_unmap_file_os(heim_octet_string *os)
55{
56    rk_xfree(os->data);
57}
58
59int
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
70static void
71print_pem_stamp(FILE *f, const char *type, const char *str)
72{
73    fprintf(f, "-----%s %s-----\n", type, str);
74}
75
76int
77hx509_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
124int
125hx509_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
151void
152hx509_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
168const char *
169hx509_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
184int
185hx509_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