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