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