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
, ':');
235 if (buf
[0] == '\0') {
239 p
= strchr(buf
, ':');
242 while (isspace((unsigned char)*p
))
244 ret
= hx509_pem_add_header(&headers
, buf
, p
);
252 if (strncmp("-----END ", buf
, 9) == 0) {
258 i
= rk_base64_decode(buf
, p
);
264 data
= erealloc(data
, len
+ i
);
265 memcpy(((char *)data
) + len
, p
, i
);
274 ret
= (*func
)(context
, type
, headers
, data
, len
, ctx
);
282 hx509_pem_free_header(headers
);
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
;
299 hx509_pem_free_header(headers
);
305 * On modern systems there's no such thing as scrubbing a file. Not this way
306 * anyways. However, for now we'll cargo-cult this along just as in lib/krb5.
309 scrub_file(int fd
, ssize_t sz
)
313 memset(buf
, 0, sizeof(buf
));
316 size_t wr
= sizeof(buf
) > sz
? (size_t)sz
: sizeof(buf
);
318 tmp
= write(fd
, buf
, wr
);
331 _hx509_erase_file(hx509_context context
, const char *fn
)
333 struct stat sb1
, sb2
;
340 /* This is based on _krb5_erase_file(), minus file locking */
341 ret
= lstat(fn
, &sb1
);
342 if (ret
== -1 && errno
== ENOENT
)
345 hx509_set_error_string(context
, 0, errno
, "hx509_certs_destroy: "
346 "stat of \"%s\": %s", fn
, strerror(errno
));
350 fd
= open(fn
, O_RDWR
| O_BINARY
| O_CLOEXEC
| O_NOFOLLOW
);
352 return errno
== ENOENT
? 0 : errno
;
355 if (unlink(fn
) < 0) {
358 hx509_set_error_string(context
, 0, ret
, "hx509_certs_destroy: "
359 "unlinking \"%s\": %s", fn
, strerror(ret
));
363 /* check TOCTOU, symlinks */
364 ret
= fstat(fd
, &sb2
);
367 hx509_set_error_string(context
, 0, ret
, "hx509_certs_destroy: "
368 "fstat of %d, \"%s\": %s", fd
, fn
,
373 if (sb1
.st_dev
!= sb2
.st_dev
|| sb1
.st_ino
!= sb2
.st_ino
) {
378 /* there are still hard links to this file */
379 if (sb2
.st_nlink
!= 0) {
384 ret
= scrub_file(fd
, sb2
.st_size
);