xref: /titanic_50/usr/src/lib/libcryptoutil/common/keyfile.c (revision 1c9bd843ebc00801cc418156a3893362a1dc872e)
1*1c9bd843Sdinak /*
2*1c9bd843Sdinak  * CDDL HEADER START
3*1c9bd843Sdinak  *
4*1c9bd843Sdinak  * The contents of this file are subject to the terms of the
5*1c9bd843Sdinak  * Common Development and Distribution License (the "License").
6*1c9bd843Sdinak  * You may not use this file except in compliance with the License.
7*1c9bd843Sdinak  *
8*1c9bd843Sdinak  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1c9bd843Sdinak  * or http://www.opensolaris.org/os/licensing.
10*1c9bd843Sdinak  * See the License for the specific language governing permissions
11*1c9bd843Sdinak  * and limitations under the License.
12*1c9bd843Sdinak  *
13*1c9bd843Sdinak  * When distributing Covered Code, include this CDDL HEADER in each
14*1c9bd843Sdinak  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1c9bd843Sdinak  * If applicable, add the following below this CDDL HEADER, with the
16*1c9bd843Sdinak  * fields enclosed by brackets "[]" replaced with your own identifying
17*1c9bd843Sdinak  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1c9bd843Sdinak  *
19*1c9bd843Sdinak  * CDDL HEADER END
20*1c9bd843Sdinak  */
21*1c9bd843Sdinak /*
22*1c9bd843Sdinak  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*1c9bd843Sdinak  * Use is subject to license terms.
24*1c9bd843Sdinak  */
25*1c9bd843Sdinak 
26*1c9bd843Sdinak #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*1c9bd843Sdinak 
28*1c9bd843Sdinak #include <stdio.h>
29*1c9bd843Sdinak #include <string.h>
30*1c9bd843Sdinak #include <fcntl.h>
31*1c9bd843Sdinak #include <sys/types.h>
32*1c9bd843Sdinak #include <sys/stat.h>
33*1c9bd843Sdinak #include <errno.h>
34*1c9bd843Sdinak #include <locale.h>
35*1c9bd843Sdinak #include <cryptoutil.h>
36*1c9bd843Sdinak 
37*1c9bd843Sdinak /*
38*1c9bd843Sdinak  * Read file into buffer.  Used to read raw key data or initialization
39*1c9bd843Sdinak  * vector data.  Buffer must be freed by caller using free().
40*1c9bd843Sdinak  *
41*1c9bd843Sdinak  * If file is a regular file, entire file is read and dlen is set
42*1c9bd843Sdinak  * to the number of bytes read.  Otherwise, dlen should first be set
43*1c9bd843Sdinak  * to the number of bytes requested and will be reset to actual number
44*1c9bd843Sdinak  * of bytes returned.
45*1c9bd843Sdinak  *
46*1c9bd843Sdinak  * Return 0 on success, -1 on error.
47*1c9bd843Sdinak  */
48*1c9bd843Sdinak int
49*1c9bd843Sdinak pkcs11_read_data(char *filename, void **dbuf, size_t *dlen)
50*1c9bd843Sdinak {
51*1c9bd843Sdinak 	int	fd;
52*1c9bd843Sdinak 	struct stat statbuf;
53*1c9bd843Sdinak 	boolean_t plain_file;
54*1c9bd843Sdinak 	void	*filebuf = NULL;
55*1c9bd843Sdinak 	size_t	filesize = 0;
56*1c9bd843Sdinak 
57*1c9bd843Sdinak 	if (filename == NULL || dbuf == NULL || dlen == NULL)
58*1c9bd843Sdinak 		return (-1);
59*1c9bd843Sdinak 
60*1c9bd843Sdinak 	if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) {
61*1c9bd843Sdinak 		cryptoerror(LOG_STDERR, gettext("cannot open %s"), filename);
62*1c9bd843Sdinak 		return (-1);
63*1c9bd843Sdinak 	}
64*1c9bd843Sdinak 
65*1c9bd843Sdinak 	if (fstat(fd, &statbuf) == -1) {
66*1c9bd843Sdinak 		cryptoerror(LOG_STDERR, gettext("cannot stat %s"), filename);
67*1c9bd843Sdinak 		(void) close(fd);
68*1c9bd843Sdinak 		return (-1);
69*1c9bd843Sdinak 	}
70*1c9bd843Sdinak 
71*1c9bd843Sdinak 	if (S_ISREG(statbuf.st_mode)) {
72*1c9bd843Sdinak 		/* read the entire regular file */
73*1c9bd843Sdinak 		filesize = statbuf.st_size;
74*1c9bd843Sdinak 		plain_file = B_TRUE;
75*1c9bd843Sdinak 	} else {
76*1c9bd843Sdinak 		/* read requested bytes from special file */
77*1c9bd843Sdinak 		filesize = *dlen;
78*1c9bd843Sdinak 		plain_file = B_FALSE;
79*1c9bd843Sdinak 	}
80*1c9bd843Sdinak 
81*1c9bd843Sdinak 	if (filesize == 0) {
82*1c9bd843Sdinak 		/*
83*1c9bd843Sdinak 		 * for decrypt this is an error; for digest this is ok;
84*1c9bd843Sdinak 		 * make it ok here but also set dbuf = NULL and dlen = 0
85*1c9bd843Sdinak 		 * to indicate there was no data to read and caller can
86*1c9bd843Sdinak 		 * retranslate that to an error if it wishes.
87*1c9bd843Sdinak 		 */
88*1c9bd843Sdinak 		(void) close(fd);
89*1c9bd843Sdinak 		*dbuf = NULL;
90*1c9bd843Sdinak 		*dlen = 0;
91*1c9bd843Sdinak 		return (0);
92*1c9bd843Sdinak 	}
93*1c9bd843Sdinak 
94*1c9bd843Sdinak 	if ((filebuf = malloc(filesize)) == NULL) {
95*1c9bd843Sdinak 		int	err = errno;
96*1c9bd843Sdinak 		cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err));
97*1c9bd843Sdinak 		(void) close(fd);
98*1c9bd843Sdinak 		return (-1);
99*1c9bd843Sdinak 	}
100*1c9bd843Sdinak 
101*1c9bd843Sdinak 	if (plain_file) {
102*1c9bd843Sdinak 		/* either it got read or it didn't */
103*1c9bd843Sdinak 		if (read(fd, filebuf, filesize) != filesize) {
104*1c9bd843Sdinak 			int	err = errno;
105*1c9bd843Sdinak 			cryptoerror(LOG_STDERR,
106*1c9bd843Sdinak 			    gettext("error reading file %s: %s"), filename,
107*1c9bd843Sdinak 			    strerror(err));
108*1c9bd843Sdinak 			(void) close(fd);
109*1c9bd843Sdinak 			return (-1);
110*1c9bd843Sdinak 		}
111*1c9bd843Sdinak 	} else {
112*1c9bd843Sdinak 		/* reading from special file may need some coaxing */
113*1c9bd843Sdinak 		char	*marker = (char *)filebuf;
114*1c9bd843Sdinak 		size_t	left = filesize;
115*1c9bd843Sdinak 		ssize_t	nread;
116*1c9bd843Sdinak 		int	err;
117*1c9bd843Sdinak 
118*1c9bd843Sdinak 		for (/* */; left > 0; marker += nread, left -= nread) {
119*1c9bd843Sdinak 			/* keep reading it's going well */
120*1c9bd843Sdinak 			nread = read(fd, marker, left);
121*1c9bd843Sdinak 			if (nread > 0 || (nread == 0 && errno == EINTR))
122*1c9bd843Sdinak 				continue;
123*1c9bd843Sdinak 
124*1c9bd843Sdinak 			/* might have to be good enough for caller */
125*1c9bd843Sdinak 			if (nread == 0 && errno == EAGAIN)
126*1c9bd843Sdinak 				break;
127*1c9bd843Sdinak 
128*1c9bd843Sdinak 			/* anything else is an error */
129*1c9bd843Sdinak 			err = errno;
130*1c9bd843Sdinak 			cryptoerror(LOG_STDERR,
131*1c9bd843Sdinak 			    gettext("error reading file %s: %s"), filename,
132*1c9bd843Sdinak 			    strerror(err));
133*1c9bd843Sdinak 			(void) close(fd);
134*1c9bd843Sdinak 			return (-1);
135*1c9bd843Sdinak 		}
136*1c9bd843Sdinak 		/* reset to actual number of bytes read */
137*1c9bd843Sdinak 		filesize -= left;
138*1c9bd843Sdinak 	}
139*1c9bd843Sdinak 
140*1c9bd843Sdinak 	(void) close(fd);
141*1c9bd843Sdinak 	*dbuf = filebuf;
142*1c9bd843Sdinak 	*dlen = filesize;
143*1c9bd843Sdinak 	return (0);
144*1c9bd843Sdinak }
145