2 * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
36 HX509_LIB_FUNCTION
int HX509_LIB_CALL
37 _hx509_map_file_os(const char *fn
, heim_octet_string
*os
)
43 ret
= rk_undumpdata(fn
, &data
, &length
);
51 HX509_LIB_FUNCTION
void HX509_LIB_CALL
52 _hx509_unmap_file_os(heim_octet_string
*os
)
57 HX509_LIB_FUNCTION
int HX509_LIB_CALL
58 _hx509_write_file(const char *fn
, const void *data
, size_t length
)
60 rk_dumpdata(fn
, data
, length
);
69 print_pem_stamp(FILE *f
, const char *type
, const char *str
)
71 fprintf(f
, "-----%s %s-----\n", type
, str
);
74 HX509_LIB_FUNCTION
int HX509_LIB_CALL
75 hx509_pem_write(hx509_context context
, const char *type
,
76 hx509_pem_header
*headers
, FILE *f
,
77 const void *data
, size_t size
)
83 #define ENCODE_LINE_LENGTH 54
85 print_pem_stamp(f
, "BEGIN", type
);
88 fprintf(f
, "%s: %s\n%s",
89 headers
->header
, headers
->value
,
90 headers
->next
? "" : "\n");
91 headers
= headers
->next
;
98 if (length
> ENCODE_LINE_LENGTH
)
99 length
= ENCODE_LINE_LENGTH
;
101 l
= rk_base64_encode(p
, length
, &line
);
103 hx509_set_error_string(context
, 0, ENOMEM
,
104 "malloc - out of memory");
108 fprintf(f
, "%s\n", line
);
113 print_pem_stamp(f
, "END", type
);
122 HX509_LIB_FUNCTION
int HX509_LIB_CALL
123 hx509_pem_add_header(hx509_pem_header
**headers
,
124 const char *header
, const char *value
)
128 h
= calloc(1, sizeof(*h
));
131 h
->header
= strdup(header
);
132 if (h
->header
== NULL
) {
136 h
->value
= strdup(value
);
137 if (h
->value
== NULL
) {
149 HX509_LIB_FUNCTION
void HX509_LIB_CALL
150 hx509_pem_free_header(hx509_pem_header
*headers
)
155 headers
= headers
->next
;
166 HX509_LIB_FUNCTION
const char * HX509_LIB_CALL
167 hx509_pem_find_header(const hx509_pem_header
*h
, const char *header
)
170 if (strcmp(header
, h
->header
) == 0)
182 HX509_LIB_FUNCTION
int HX509_LIB_CALL
183 hx509_pem_read(hx509_context context
,
185 hx509_pem_read_func func
,
188 hx509_pem_header
*headers
= NULL
;
193 int ret
= HX509_PARSING_KEY_FAILED
;
195 enum { BEFORE
, SEARCHHEADER
, INHEADER
, INDATA
, DONE
} where
;
199 while (fgets(buf
, sizeof(buf
), f
) != NULL
) {
203 i
= strcspn(buf
, "\n");
204 if (buf
[i
] == '\n') {
209 if (buf
[i
] == '\r') {
217 if (strncmp("-----BEGIN ", buf
, 11) == 0) {
218 type
= strdup(buf
+ 11);
221 p
= strchr(type
, '-');
224 where
= SEARCHHEADER
;
228 p
= strchr(buf
, ':');
236 if (buf
[0] == '\0') {
240 p
= strchr(buf
, ':');
243 while (isspace((int)*p
))
245 ret
= hx509_pem_add_header(&headers
, buf
, p
);
253 if (strncmp("-----END ", buf
, 9) == 0) {
259 i
= rk_base64_decode(buf
, p
);
265 data
= erealloc(data
, len
+ i
);
266 memcpy(((char *)data
) + len
, p
, i
);
275 ret
= (*func
)(context
, type
, headers
, data
, len
, ctx
);
283 hx509_pem_free_header(headers
);
290 if (where
!= BEFORE
) {
291 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
292 "File ends before end of PEM end tag");
293 ret
= HX509_PARSING_KEY_FAILED
;
300 hx509_pem_free_header(headers
);
306 * On modern systems there's no such thing as scrubbing a file. Not this way
307 * anyways. However, for now we'll cargo-cult this along just as in lib/krb5.
310 scrub_file(int fd
, ssize_t sz
)
314 memset(buf
, 0, sizeof(buf
));
317 size_t wr
= sizeof(buf
) > sz
? (size_t)sz
: sizeof(buf
);
319 tmp
= write(fd
, buf
, wr
);
332 _hx509_erase_file(hx509_context context
, const char *fn
)
334 struct stat sb1
, sb2
;
341 /* This is based on _krb5_erase_file(), minus file locking */
342 ret
= lstat(fn
, &sb1
);
343 if (ret
== -1 && errno
== ENOENT
)
346 hx509_set_error_string(context
, 0, ret
, "hx509_certs_destroy: "
347 "stat of \"%s\": %s", fn
, strerror(ret
));
351 fd
= open(fn
, O_RDWR
| O_BINARY
| O_CLOEXEC
| O_NOFOLLOW
);
353 if (ret
== -1 && errno
== ENOENT
)
358 if (unlink(fn
) < 0) {
361 hx509_set_error_string(context
, 0, ret
, "hx509_certs_destroy: "
362 "unlinking \"%s\": %s", fn
, strerror(ret
));
366 /* check TOCTOU, symlinks */
367 ret
= fstat(fd
, &sb2
);
370 hx509_set_error_string(context
, 0, ret
, "hx509_certs_destroy: "
371 "fstat of %d, \"%s\": %s", fd
, fn
,
376 if (sb1
.st_dev
!= sb2
.st_dev
|| sb1
.st_ino
!= sb2
.st_ino
) {
381 /* there are still hard links to this file */
382 if (sb2
.st_nlink
!= 0) {
387 ret
= scrub_file(fd
, sb2
.st_size
);