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