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 36 int 37 _hx509_map_file_os(const char *fn, heim_octet_string *os) 38 { 39 size_t length; 40 void *data; 41 int ret; 42 43 ret = rk_undumpdata(fn, &data, &length); 44 45 os->data = data; 46 os->length = length; 47 48 return ret; 49 } 50 51 void 52 _hx509_unmap_file_os(heim_octet_string *os) 53 { 54 rk_xfree(os->data); 55 } 56 57 int 58 _hx509_write_file(const char *fn, const void *data, size_t length) 59 { 60 rk_dumpdata(fn, data, length); 61 return 0; 62 } 63 64 /* 65 * 66 */ 67 68 static void 69 print_pem_stamp(FILE *f, const char *type, const char *str) 70 { 71 fprintf(f, "-----%s %s-----\n", type, str); 72 } 73 74 int 75 hx509_pem_write(hx509_context context, const char *type, 76 hx509_pem_header *headers, FILE *f, 77 const void *data, size_t size) 78 { 79 const char *p = data; 80 size_t length; 81 char *line; 82 83 #define ENCODE_LINE_LENGTH 54 84 85 print_pem_stamp(f, "BEGIN", type); 86 87 while (headers) { 88 fprintf(f, "%s: %s\n%s", 89 headers->header, headers->value, 90 headers->next ? "" : "\n"); 91 headers = headers->next; 92 } 93 94 while (size > 0) { 95 ssize_t l; 96 97 length = size; 98 if (length > ENCODE_LINE_LENGTH) 99 length = ENCODE_LINE_LENGTH; 100 101 l = base64_encode(p, length, &line); 102 if (l < 0) { 103 hx509_set_error_string(context, 0, ENOMEM, 104 "malloc - out of memory"); 105 return ENOMEM; 106 } 107 size -= length; 108 fprintf(f, "%s\n", line); 109 p += length; 110 free(line); 111 } 112 113 print_pem_stamp(f, "END", type); 114 115 return 0; 116 } 117 118 /* 119 * 120 */ 121 122 int 123 hx509_pem_add_header(hx509_pem_header **headers, 124 const char *header, const char *value) 125 { 126 hx509_pem_header *h; 127 128 h = calloc(1, sizeof(*h)); 129 if (h == NULL) 130 return ENOMEM; 131 h->header = strdup(header); 132 if (h->header == NULL) { 133 free(h); 134 return ENOMEM; 135 } 136 h->value = strdup(value); 137 if (h->value == NULL) { 138 free(h->header); 139 free(h); 140 return ENOMEM; 141 } 142 143 h->next = *headers; 144 *headers = h; 145 146 return 0; 147 } 148 149 void 150 hx509_pem_free_header(hx509_pem_header *headers) 151 { 152 hx509_pem_header *h; 153 while (headers) { 154 h = headers; 155 headers = headers->next; 156 free(h->header); 157 free(h->value); 158 free(h); 159 } 160 } 161 162 /* 163 * 164 */ 165 166 const char * 167 hx509_pem_find_header(const hx509_pem_header *h, const char *header) 168 { 169 while(h) { 170 if (strcmp(header, h->header) == 0) 171 return h->value; 172 h = h->next; 173 } 174 return NULL; 175 } 176 177 178 /* 179 * 180 */ 181 182 int 183 hx509_pem_read(hx509_context context, 184 FILE *f, 185 hx509_pem_read_func func, 186 void *ctx) 187 { 188 hx509_pem_header *headers = NULL; 189 char *type = NULL; 190 void *data = NULL; 191 size_t len = 0; 192 char buf[1024]; 193 int ret = HX509_PARSING_KEY_FAILED; 194 195 enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; 196 197 where = BEFORE; 198 199 while (fgets(buf, sizeof(buf), f) != NULL) { 200 char *p; 201 int i; 202 203 i = strcspn(buf, "\n"); 204 if (buf[i] == '\n') { 205 buf[i] = '\0'; 206 if (i > 0) 207 i--; 208 } 209 if (buf[i] == '\r') { 210 buf[i] = '\0'; 211 if (i > 0) 212 i--; 213 } 214 215 switch (where) { 216 case BEFORE: 217 if (strncmp("-----BEGIN ", buf, 11) == 0) { 218 type = strdup(buf + 11); 219 if (type == NULL) 220 break; 221 p = strchr(type, '-'); 222 if (p) 223 *p = '\0'; 224 where = SEARCHHEADER; 225 } 226 break; 227 case SEARCHHEADER: 228 p = strchr(buf, ':'); 229 if (p == NULL) { 230 where = INDATA; 231 goto indata; 232 } 233 /* FALLTHOUGH */ 234 case INHEADER: 235 if (buf[0] == '\0') { 236 where = INDATA; 237 break; 238 } 239 p = strchr(buf, ':'); 240 if (p) { 241 *p++ = '\0'; 242 while (isspace((int)*p)) 243 p++; 244 ret = hx509_pem_add_header(&headers, buf, p); 245 if (ret) 246 abort(); 247 } 248 break; 249 case INDATA: 250 indata: 251 252 if (strncmp("-----END ", buf, 9) == 0) { 253 where = DONE; 254 break; 255 } 256 257 p = emalloc(i); 258 i = base64_decode(buf, p); 259 if (i < 0) { 260 free(p); 261 goto out; 262 } 263 264 data = erealloc(data, len + i); 265 memcpy(((char *)data) + len, p, i); 266 free(p); 267 len += i; 268 break; 269 case DONE: 270 abort(); 271 } 272 273 if (where == DONE) { 274 ret = (*func)(context, type, headers, data, len, ctx); 275 out: 276 free(data); 277 data = NULL; 278 len = 0; 279 free(type); 280 type = NULL; 281 where = BEFORE; 282 hx509_pem_free_header(headers); 283 headers = NULL; 284 if (ret) 285 break; 286 } 287 } 288 289 if (where != BEFORE) { 290 hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, 291 "File ends before end of PEM end tag"); 292 ret = HX509_PARSING_KEY_FAILED; 293 } 294 if (data) 295 free(data); 296 if (type) 297 free(type); 298 if (headers) 299 hx509_pem_free_header(headers); 300 301 return ret; 302 } 303