Home | History | Annotate | Line # | Download | only in hx509
      1 /*	$NetBSD: file.c,v 1.3 2023/06/19 21:41:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2005 - 2006 Kungliga Tekniska Hgskolan
      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 
     38 int
     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 
     53 void
     54 _hx509_unmap_file_os(heim_octet_string *os)
     55 {
     56     rk_xfree(os->data);
     57 }
     58 
     59 int
     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 
     70 static void
     71 print_pem_stamp(FILE *f, const char *type, const char *str)
     72 {
     73     fprintf(f, "-----%s %s-----\n", type, str);
     74 }
     75 
     76 int
     77 hx509_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 = rk_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 
    124 int
    125 hx509_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 
    151 void
    152 hx509_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 
    168 const char *
    169 hx509_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 
    184 int
    185 hx509_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 	    /* FALLTHROUGH */
    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 = rk_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