1178825Sdfr/* 2178825Sdfr * Copyright (c) 2005 - 2006 Kungliga Tekniska H�gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5178825Sdfr * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9178825Sdfr * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20178825Sdfr * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "hx_locl.h" 35178825SdfrRCSID("$ID$"); 36178825Sdfr 37178825Sdfrint 38178825Sdfr_hx509_map_file_os(const char *fn, heim_octet_string *os, struct stat *rsb) 39178825Sdfr{ 40178825Sdfr size_t length; 41178825Sdfr void *data; 42178825Sdfr int ret; 43178825Sdfr 44178825Sdfr ret = _hx509_map_file(fn, &data, &length, rsb); 45178825Sdfr 46178825Sdfr os->data = data; 47178825Sdfr os->length = length; 48178825Sdfr 49178825Sdfr return ret; 50178825Sdfr} 51178825Sdfr 52178825Sdfrvoid 53178825Sdfr_hx509_unmap_file_os(heim_octet_string *os) 54178825Sdfr{ 55178825Sdfr _hx509_unmap_file(os->data, os->length); 56178825Sdfr} 57178825Sdfr 58178825Sdfrint 59178825Sdfr_hx509_map_file(const char *fn, void **data, size_t *length, struct stat *rsb) 60178825Sdfr{ 61178825Sdfr struct stat sb; 62178825Sdfr size_t len; 63178825Sdfr ssize_t l; 64178825Sdfr int ret; 65178825Sdfr void *d; 66178825Sdfr int fd; 67178825Sdfr 68178825Sdfr *data = NULL; 69178825Sdfr *length = 0; 70178825Sdfr 71178825Sdfr fd = open(fn, O_RDONLY); 72178825Sdfr if (fd < 0) 73178825Sdfr return errno; 74178825Sdfr 75178825Sdfr if (fstat(fd, &sb) < 0) { 76178825Sdfr ret = errno; 77178825Sdfr close(fd); 78178825Sdfr return ret; 79178825Sdfr } 80178825Sdfr 81178825Sdfr len = sb.st_size; 82178825Sdfr 83178825Sdfr d = malloc(len); 84178825Sdfr if (d == NULL) { 85178825Sdfr close(fd); 86178825Sdfr return ENOMEM; 87178825Sdfr } 88178825Sdfr 89178825Sdfr l = read(fd, d, len); 90178825Sdfr close(fd); 91178825Sdfr if (l < 0 || l != len) { 92178825Sdfr free(d); 93178825Sdfr return EINVAL; 94178825Sdfr } 95178825Sdfr 96178825Sdfr if (rsb) 97178825Sdfr *rsb = sb; 98178825Sdfr *data = d; 99178825Sdfr *length = len; 100178825Sdfr return 0; 101178825Sdfr} 102178825Sdfr 103178825Sdfrvoid 104178825Sdfr_hx509_unmap_file(void *data, size_t len) 105178825Sdfr{ 106178825Sdfr free(data); 107178825Sdfr} 108178825Sdfr 109178825Sdfrint 110178825Sdfr_hx509_write_file(const char *fn, const void *data, size_t length) 111178825Sdfr{ 112178825Sdfr ssize_t sz; 113178825Sdfr const unsigned char *p = data; 114178825Sdfr int fd; 115178825Sdfr 116178825Sdfr fd = open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); 117178825Sdfr if (fd < 0) 118178825Sdfr return errno; 119178825Sdfr 120178825Sdfr do { 121178825Sdfr sz = write(fd, p, length); 122178825Sdfr if (sz < 0) { 123178825Sdfr int saved_errno = errno; 124178825Sdfr close(fd); 125178825Sdfr return saved_errno; 126178825Sdfr } 127178825Sdfr if (sz == 0) 128178825Sdfr break; 129178825Sdfr length -= sz; 130178825Sdfr } while (length > 0); 131178825Sdfr 132178825Sdfr if (close(fd) == -1) 133178825Sdfr return errno; 134178825Sdfr 135178825Sdfr return 0; 136178825Sdfr} 137178825Sdfr 138178825Sdfr/* 139178825Sdfr * 140178825Sdfr */ 141178825Sdfr 142178825Sdfrstatic void 143178825Sdfrheader(FILE *f, const char *type, const char *str) 144178825Sdfr{ 145178825Sdfr fprintf(f, "-----%s %s-----\n", type, str); 146178825Sdfr} 147178825Sdfr 148178825Sdfrint 149178825Sdfrhx509_pem_write(hx509_context context, const char *type, 150178825Sdfr hx509_pem_header *headers, FILE *f, 151178825Sdfr const void *data, size_t size) 152178825Sdfr{ 153178825Sdfr const char *p = data; 154178825Sdfr size_t length; 155178825Sdfr char *line; 156178825Sdfr 157178825Sdfr#define ENCODE_LINE_LENGTH 54 158178825Sdfr 159178825Sdfr header(f, "BEGIN", type); 160178825Sdfr 161178825Sdfr while (headers) { 162178825Sdfr fprintf(f, "%s: %s\n%s", 163178825Sdfr headers->header, headers->value, 164178825Sdfr headers->next ? "" : "\n"); 165178825Sdfr headers = headers->next; 166178825Sdfr } 167178825Sdfr 168178825Sdfr while (size > 0) { 169178825Sdfr ssize_t l; 170178825Sdfr 171178825Sdfr length = size; 172178825Sdfr if (length > ENCODE_LINE_LENGTH) 173178825Sdfr length = ENCODE_LINE_LENGTH; 174178825Sdfr 175178825Sdfr l = base64_encode(p, length, &line); 176178825Sdfr if (l < 0) { 177178825Sdfr hx509_set_error_string(context, 0, ENOMEM, 178178825Sdfr "malloc - out of memory"); 179178825Sdfr return ENOMEM; 180178825Sdfr } 181178825Sdfr size -= length; 182178825Sdfr fprintf(f, "%s\n", line); 183178825Sdfr p += length; 184178825Sdfr free(line); 185178825Sdfr } 186178825Sdfr 187178825Sdfr header(f, "END", type); 188178825Sdfr 189178825Sdfr return 0; 190178825Sdfr} 191178825Sdfr 192178825Sdfr/* 193178825Sdfr * 194178825Sdfr */ 195178825Sdfr 196178825Sdfrint 197178825Sdfrhx509_pem_add_header(hx509_pem_header **headers, 198178825Sdfr const char *header, const char *value) 199178825Sdfr{ 200178825Sdfr hx509_pem_header *h; 201178825Sdfr 202178825Sdfr h = calloc(1, sizeof(*h)); 203178825Sdfr if (h == NULL) 204178825Sdfr return ENOMEM; 205178825Sdfr h->header = strdup(header); 206178825Sdfr if (h->header == NULL) { 207178825Sdfr free(h); 208178825Sdfr return ENOMEM; 209178825Sdfr } 210178825Sdfr h->value = strdup(value); 211178825Sdfr if (h->value == NULL) { 212178825Sdfr free(h->header); 213178825Sdfr free(h); 214178825Sdfr return ENOMEM; 215178825Sdfr } 216178825Sdfr 217178825Sdfr h->next = *headers; 218178825Sdfr *headers = h; 219178825Sdfr 220178825Sdfr return 0; 221178825Sdfr} 222178825Sdfr 223178825Sdfrvoid 224178825Sdfrhx509_pem_free_header(hx509_pem_header *headers) 225178825Sdfr{ 226178825Sdfr hx509_pem_header *h; 227178825Sdfr while (headers) { 228178825Sdfr h = headers; 229178825Sdfr headers = headers->next; 230178825Sdfr free(h->header); 231178825Sdfr free(h->value); 232178825Sdfr free(h); 233178825Sdfr } 234178825Sdfr} 235178825Sdfr 236178825Sdfr/* 237178825Sdfr * 238178825Sdfr */ 239178825Sdfr 240178825Sdfrconst char * 241178825Sdfrhx509_pem_find_header(const hx509_pem_header *h, const char *header) 242178825Sdfr{ 243178825Sdfr while(h) { 244178825Sdfr if (strcmp(header, h->header) == 0) 245178825Sdfr return h->value; 246178825Sdfr h = h->next; 247178825Sdfr } 248178825Sdfr return NULL; 249178825Sdfr} 250178825Sdfr 251178825Sdfr 252178825Sdfr/* 253178825Sdfr * 254178825Sdfr */ 255178825Sdfr 256178825Sdfrint 257178825Sdfrhx509_pem_read(hx509_context context, 258178825Sdfr FILE *f, 259178825Sdfr hx509_pem_read_func func, 260178825Sdfr void *ctx) 261178825Sdfr{ 262178825Sdfr hx509_pem_header *headers = NULL; 263178825Sdfr char *type = NULL; 264178825Sdfr void *data = NULL; 265178825Sdfr size_t len = 0; 266178825Sdfr char buf[1024]; 267178825Sdfr int ret = HX509_PARSING_KEY_FAILED; 268178825Sdfr 269178825Sdfr enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; 270178825Sdfr 271178825Sdfr where = BEFORE; 272178825Sdfr 273178825Sdfr while (fgets(buf, sizeof(buf), f) != NULL) { 274178825Sdfr char *p; 275178825Sdfr int i; 276178825Sdfr 277178825Sdfr i = strcspn(buf, "\n"); 278178825Sdfr if (buf[i] == '\n') { 279178825Sdfr buf[i] = '\0'; 280178825Sdfr if (i > 0) 281178825Sdfr i--; 282178825Sdfr } 283178825Sdfr if (buf[i] == '\r') { 284178825Sdfr buf[i] = '\0'; 285178825Sdfr if (i > 0) 286178825Sdfr i--; 287178825Sdfr } 288178825Sdfr 289178825Sdfr switch (where) { 290178825Sdfr case BEFORE: 291178825Sdfr if (strncmp("-----BEGIN ", buf, 11) == 0) { 292178825Sdfr type = strdup(buf + 11); 293178825Sdfr if (type == NULL) 294178825Sdfr break; 295178825Sdfr p = strchr(type, '-'); 296178825Sdfr if (p) 297178825Sdfr *p = '\0'; 298178825Sdfr where = SEARCHHEADER; 299178825Sdfr } 300178825Sdfr break; 301178825Sdfr case SEARCHHEADER: 302178825Sdfr p = strchr(buf, ':'); 303178825Sdfr if (p == NULL) { 304178825Sdfr where = INDATA; 305178825Sdfr goto indata; 306178825Sdfr } 307178825Sdfr /* FALLTHOUGH */ 308178825Sdfr case INHEADER: 309178825Sdfr if (buf[0] == '\0') { 310178825Sdfr where = INDATA; 311178825Sdfr break; 312178825Sdfr } 313178825Sdfr p = strchr(buf, ':'); 314178825Sdfr if (p) { 315178825Sdfr *p++ = '\0'; 316178825Sdfr while (isspace((int)*p)) 317178825Sdfr p++; 318178825Sdfr ret = hx509_pem_add_header(&headers, buf, p); 319178825Sdfr if (ret) 320178825Sdfr abort(); 321178825Sdfr } 322178825Sdfr break; 323178825Sdfr case INDATA: 324178825Sdfr indata: 325178825Sdfr 326178825Sdfr if (strncmp("-----END ", buf, 9) == 0) { 327178825Sdfr where = DONE; 328178825Sdfr break; 329178825Sdfr } 330178825Sdfr 331178825Sdfr p = emalloc(i); 332178825Sdfr i = base64_decode(buf, p); 333178825Sdfr if (i < 0) { 334178825Sdfr free(p); 335178825Sdfr goto out; 336178825Sdfr } 337178825Sdfr 338178825Sdfr data = erealloc(data, len + i); 339178825Sdfr memcpy(((char *)data) + len, p, i); 340178825Sdfr free(p); 341178825Sdfr len += i; 342178825Sdfr break; 343178825Sdfr case DONE: 344178825Sdfr abort(); 345178825Sdfr } 346178825Sdfr 347178825Sdfr if (where == DONE) { 348178825Sdfr ret = (*func)(context, type, headers, data, len, ctx); 349178825Sdfr out: 350178825Sdfr free(data); 351178825Sdfr data = NULL; 352178825Sdfr len = 0; 353178825Sdfr free(type); 354178825Sdfr type = NULL; 355178825Sdfr where = BEFORE; 356178825Sdfr hx509_pem_free_header(headers); 357178825Sdfr headers = NULL; 358178825Sdfr if (ret) 359178825Sdfr break; 360178825Sdfr } 361178825Sdfr } 362178825Sdfr 363178825Sdfr if (where != BEFORE) { 364178825Sdfr hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, 365178825Sdfr "File ends before end of PEM end tag"); 366178825Sdfr ret = HX509_PARSING_KEY_FAILED; 367178825Sdfr } 368178825Sdfr if (data) 369178825Sdfr free(data); 370178825Sdfr if (type) 371178825Sdfr free(type); 372178825Sdfr if (headers) 373178825Sdfr hx509_pem_free_header(headers); 374178825Sdfr 375178825Sdfr return ret; 376178825Sdfr} 377