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, struct stat *rsb) 39 { 40 size_t length; 41 void *data; 42 int ret; 43 44 ret = _hx509_map_file(fn, &data, &length, rsb); 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 _hx509_unmap_file(os->data, os->length); 56 } 57 58 int 59 _hx509_map_file(const char *fn, void **data, size_t *length, struct stat *rsb) 60 { 61 struct stat sb; 62 size_t len; 63 ssize_t l; 64 int ret; 65 void *d; 66 int fd; 67 68 *data = NULL; 69 *length = 0; 70 71 fd = open(fn, O_RDONLY); 72 if (fd < 0) 73 return errno; 74 75 if (fstat(fd, &sb) < 0) { 76 ret = errno; 77 close(fd); 78 return ret; 79 } 80 81 len = sb.st_size; 82 83 d = malloc(len); 84 if (d == NULL) { 85 close(fd); 86 return ENOMEM; 87 } 88 89 l = read(fd, d, len); 90 close(fd); 91 if (l < 0 || l != len) { 92 free(d); 93 return EINVAL; 94 } 95 96 if (rsb) 97 *rsb = sb; 98 *data = d; 99 *length = len; 100 return 0; 101 } 102 103 void 104 _hx509_unmap_file(void *data, size_t len) 105 { 106 free(data); 107 } 108 109 int 110 _hx509_write_file(const char *fn, const void *data, size_t length) 111 { 112 ssize_t sz; 113 const unsigned char *p = data; 114 int fd; 115 116 fd = open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); 117 if (fd < 0) 118 return errno; 119 120 do { 121 sz = write(fd, p, length); 122 if (sz < 0) { 123 int saved_errno = errno; 124 close(fd); 125 return saved_errno; 126 } 127 if (sz == 0) 128 break; 129 length -= sz; 130 } while (length > 0); 131 132 if (close(fd) == -1) 133 return errno; 134 135 return 0; 136 } 137 138 /* 139 * 140 */ 141 142 static void 143 header(FILE *f, const char *type, const char *str) 144 { 145 fprintf(f, "-----%s %s-----\n", type, str); 146 } 147 148 int 149 hx509_pem_write(hx509_context context, const char *type, 150 hx509_pem_header *headers, FILE *f, 151 const void *data, size_t size) 152 { 153 const char *p = data; 154 size_t length; 155 char *line; 156 157 #define ENCODE_LINE_LENGTH 54 158 159 header(f, "BEGIN", type); 160 161 while (headers) { 162 fprintf(f, "%s: %s\n%s", 163 headers->header, headers->value, 164 headers->next ? "" : "\n"); 165 headers = headers->next; 166 } 167 168 while (size > 0) { 169 ssize_t l; 170 171 length = size; 172 if (length > ENCODE_LINE_LENGTH) 173 length = ENCODE_LINE_LENGTH; 174 175 l = base64_encode(p, length, &line); 176 if (l < 0) { 177 hx509_set_error_string(context, 0, ENOMEM, 178 "malloc - out of memory"); 179 return ENOMEM; 180 } 181 size -= length; 182 fprintf(f, "%s\n", line); 183 p += length; 184 free(line); 185 } 186 187 header(f, "END", type); 188 189 return 0; 190 } 191 192 /* 193 * 194 */ 195 196 int 197 hx509_pem_add_header(hx509_pem_header **headers, 198 const char *header, const char *value) 199 { 200 hx509_pem_header *h; 201 202 h = calloc(1, sizeof(*h)); 203 if (h == NULL) 204 return ENOMEM; 205 h->header = strdup(header); 206 if (h->header == NULL) { 207 free(h); 208 return ENOMEM; 209 } 210 h->value = strdup(value); 211 if (h->value == NULL) { 212 free(h->header); 213 free(h); 214 return ENOMEM; 215 } 216 217 h->next = *headers; 218 *headers = h; 219 220 return 0; 221 } 222 223 void 224 hx509_pem_free_header(hx509_pem_header *headers) 225 { 226 hx509_pem_header *h; 227 while (headers) { 228 h = headers; 229 headers = headers->next; 230 free(h->header); 231 free(h->value); 232 free(h); 233 } 234 } 235 236 /* 237 * 238 */ 239 240 const char * 241 hx509_pem_find_header(const hx509_pem_header *h, const char *header) 242 { 243 while(h) { 244 if (strcmp(header, h->header) == 0) 245 return h->value; 246 h = h->next; 247 } 248 return NULL; 249 } 250 251 252 /* 253 * 254 */ 255 256 int 257 hx509_pem_read(hx509_context context, 258 FILE *f, 259 hx509_pem_read_func func, 260 void *ctx) 261 { 262 hx509_pem_header *headers = NULL; 263 char *type = NULL; 264 void *data = NULL; 265 size_t len = 0; 266 char buf[1024]; 267 int ret = HX509_PARSING_KEY_FAILED; 268 269 enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; 270 271 where = BEFORE; 272 273 while (fgets(buf, sizeof(buf), f) != NULL) { 274 char *p; 275 int i; 276 277 i = strcspn(buf, "\n"); 278 if (buf[i] == '\n') { 279 buf[i] = '\0'; 280 if (i > 0) 281 i--; 282 } 283 if (buf[i] == '\r') { 284 buf[i] = '\0'; 285 if (i > 0) 286 i--; 287 } 288 289 switch (where) { 290 case BEFORE: 291 if (strncmp("-----BEGIN ", buf, 11) == 0) { 292 type = strdup(buf + 11); 293 if (type == NULL) 294 break; 295 p = strchr(type, '-'); 296 if (p) 297 *p = '\0'; 298 where = SEARCHHEADER; 299 } 300 break; 301 case SEARCHHEADER: 302 p = strchr(buf, ':'); 303 if (p == NULL) { 304 where = INDATA; 305 goto indata; 306 } 307 /* FALLTHOUGH */ 308 case INHEADER: 309 if (buf[0] == '\0') { 310 where = INDATA; 311 break; 312 } 313 p = strchr(buf, ':'); 314 if (p) { 315 *p++ = '\0'; 316 while (isspace((int)*p)) 317 p++; 318 ret = hx509_pem_add_header(&headers, buf, p); 319 if (ret) 320 abort(); 321 } 322 break; 323 case INDATA: 324 indata: 325 326 if (strncmp("-----END ", buf, 9) == 0) { 327 where = DONE; 328 break; 329 } 330 331 p = emalloc(i); 332 i = base64_decode(buf, p); 333 if (i < 0) { 334 free(p); 335 goto out; 336 } 337 338 data = erealloc(data, len + i); 339 memcpy(((char *)data) + len, p, i); 340 free(p); 341 len += i; 342 break; 343 case DONE: 344 abort(); 345 } 346 347 if (where == DONE) { 348 ret = (*func)(context, type, headers, data, len, ctx); 349 out: 350 free(data); 351 data = NULL; 352 len = 0; 353 free(type); 354 type = NULL; 355 where = BEFORE; 356 hx509_pem_free_header(headers); 357 headers = NULL; 358 if (ret) 359 break; 360 } 361 } 362 363 if (where != BEFORE) { 364 hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, 365 "File ends before end of PEM end tag"); 366 ret = HX509_PARSING_KEY_FAILED; 367 } 368 if (data) 369 free(data); 370 if (type) 371 free(type); 372 if (headers) 373 hx509_pem_free_header(headers); 374 375 return ret; 376 } 377