1*2dc23587SToomas Soome /*
2*2dc23587SToomas Soome  * CDDL HEADER START
3*2dc23587SToomas Soome  *
4*2dc23587SToomas Soome  * The contents of this file are subject to the terms of the
5*2dc23587SToomas Soome  * Common Development and Distribution License (the "License").
6*2dc23587SToomas Soome  * You may not use this file except in compliance with the License.
7*2dc23587SToomas Soome  *
8*2dc23587SToomas Soome  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2dc23587SToomas Soome  * or http://www.opensolaris.org/os/licensing.
10*2dc23587SToomas Soome  * See the License for the specific language governing permissions
11*2dc23587SToomas Soome  * and limitations under the License.
12*2dc23587SToomas Soome  *
13*2dc23587SToomas Soome  * When distributing Covered Code, include this CDDL HEADER in each
14*2dc23587SToomas Soome  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2dc23587SToomas Soome  * If applicable, add the following below this CDDL HEADER, with the
16*2dc23587SToomas Soome  * fields enclosed by brackets "[]" replaced with your own identifying
17*2dc23587SToomas Soome  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2dc23587SToomas Soome  *
19*2dc23587SToomas Soome  * CDDL HEADER END
20*2dc23587SToomas Soome  */
21*2dc23587SToomas Soome /*
22*2dc23587SToomas Soome  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23*2dc23587SToomas Soome  * Use is subject to license terms.
24*2dc23587SToomas Soome  */
25*2dc23587SToomas Soome /*
26*2dc23587SToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
27*2dc23587SToomas Soome  */
28*2dc23587SToomas Soome 
29*2dc23587SToomas Soome /*
30*2dc23587SToomas Soome  * Create sha1 hash for file.
31*2dc23587SToomas Soome  */
32*2dc23587SToomas Soome 
33*2dc23587SToomas Soome #include <stdio.h>
34*2dc23587SToomas Soome #include <errno.h>
35*2dc23587SToomas Soome #include <string.h>
36*2dc23587SToomas Soome #include <sys/types.h>
37*2dc23587SToomas Soome #include <sys/stat.h>
38*2dc23587SToomas Soome #include <fcntl.h>
39*2dc23587SToomas Soome #include <security/cryptoki.h>
40*2dc23587SToomas Soome #include <cryptoutil.h>
41*2dc23587SToomas Soome #include <locale.h>
42*2dc23587SToomas Soome #include "bootadm.h"
43*2dc23587SToomas Soome 
44*2dc23587SToomas Soome #define	BUFFERSIZE	(1024 * 64)
45*2dc23587SToomas Soome #define	RESULTLEN	(512)
46*2dc23587SToomas Soome static CK_BYTE buf[BUFFERSIZE];
47*2dc23587SToomas Soome 
48*2dc23587SToomas Soome /*
49*2dc23587SToomas Soome  * do_digest - Compute digest of a file. Borrowed from digest.
50*2dc23587SToomas Soome  *
51*2dc23587SToomas Soome  *  hSession - session
52*2dc23587SToomas Soome  *  pmech - ptr to mechanism to be used for digest
53*2dc23587SToomas Soome  *  fd  - file descriptor
54*2dc23587SToomas Soome  *  pdigest - buffer  where digest result is returned
55*2dc23587SToomas Soome  *  pdigestlen - length of digest buffer on input,
56*2dc23587SToomas Soome  *               length of result on output
57*2dc23587SToomas Soome  */
58*2dc23587SToomas Soome static CK_RV
59*2dc23587SToomas Soome do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
60*2dc23587SToomas Soome     int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen)
61*2dc23587SToomas Soome {
62*2dc23587SToomas Soome 	CK_RV rv;
63*2dc23587SToomas Soome 	ssize_t nread;
64*2dc23587SToomas Soome 	int err;
65*2dc23587SToomas Soome 
66*2dc23587SToomas Soome 	if ((rv = C_DigestInit(hSession, pmech)) != CKR_OK) {
67*2dc23587SToomas Soome 		return (rv);
68*2dc23587SToomas Soome 	}
69*2dc23587SToomas Soome 
70*2dc23587SToomas Soome 	while ((nread = read(fd, buf, sizeof (buf))) > 0) {
71*2dc23587SToomas Soome 		/* Get the digest */
72*2dc23587SToomas Soome 		rv = C_DigestUpdate(hSession, buf, (CK_ULONG)nread);
73*2dc23587SToomas Soome 		if (rv != CKR_OK)
74*2dc23587SToomas Soome 			return (rv);
75*2dc23587SToomas Soome 	}
76*2dc23587SToomas Soome 
77*2dc23587SToomas Soome 	/* There was a read error */
78*2dc23587SToomas Soome 	if (nread == -1) {
79*2dc23587SToomas Soome 		err = errno;
80*2dc23587SToomas Soome 		bam_print(gettext("error reading file: %s\n"), strerror(err));
81*2dc23587SToomas Soome 		return (CKR_GENERAL_ERROR);
82*2dc23587SToomas Soome 	}
83*2dc23587SToomas Soome 
84*2dc23587SToomas Soome 	rv = C_DigestFinal(hSession, *pdigest, pdigestlen);
85*2dc23587SToomas Soome 
86*2dc23587SToomas Soome 	/* result too big to fit? Allocate a bigger buffer */
87*2dc23587SToomas Soome 	if (rv == CKR_BUFFER_TOO_SMALL) {
88*2dc23587SToomas Soome 		*pdigest = realloc(*pdigest, *pdigestlen);
89*2dc23587SToomas Soome 
90*2dc23587SToomas Soome 		if (*pdigest == NULL) {
91*2dc23587SToomas Soome 			err = errno;
92*2dc23587SToomas Soome 			bam_print(gettext("realloc: %s\n"), strerror(err));
93*2dc23587SToomas Soome 			return (CKR_HOST_MEMORY);
94*2dc23587SToomas Soome 		}
95*2dc23587SToomas Soome 
96*2dc23587SToomas Soome 		rv = C_DigestFinal(hSession, *pdigest, pdigestlen);
97*2dc23587SToomas Soome 	}
98*2dc23587SToomas Soome 
99*2dc23587SToomas Soome 	return (rv);
100*2dc23587SToomas Soome }
101*2dc23587SToomas Soome 
102*2dc23587SToomas Soome int
103*2dc23587SToomas Soome bootadm_digest(const char *filename, char **result)
104*2dc23587SToomas Soome {
105*2dc23587SToomas Soome 	int fd;
106*2dc23587SToomas Soome 	CK_RV rv;
107*2dc23587SToomas Soome 	CK_ULONG slotcount;
108*2dc23587SToomas Soome 	CK_SLOT_ID slotID;
109*2dc23587SToomas Soome 	CK_SLOT_ID_PTR pSlotList = NULL;
110*2dc23587SToomas Soome 	CK_MECHANISM_TYPE mech_type = CKM_SHA_1;
111*2dc23587SToomas Soome 	CK_MECHANISM_INFO info;
112*2dc23587SToomas Soome 	CK_MECHANISM mech;
113*2dc23587SToomas Soome 	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
114*2dc23587SToomas Soome 	CK_BYTE_PTR resultbuf = NULL;
115*2dc23587SToomas Soome 	CK_ULONG resultlen;
116*2dc23587SToomas Soome 	char *resultstr = NULL;
117*2dc23587SToomas Soome 	int resultstrlen;
118*2dc23587SToomas Soome 	int i, exitcode;
119*2dc23587SToomas Soome 
120*2dc23587SToomas Soome 	/* Initialize, and get list of slots */
121*2dc23587SToomas Soome 	rv = C_Initialize(NULL);
122*2dc23587SToomas Soome 	if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
123*2dc23587SToomas Soome 		bam_print(gettext(
124*2dc23587SToomas Soome 		    "failed to initialize PKCS #11 framework: %s\n"),
125*2dc23587SToomas Soome 		    pkcs11_strerror(rv));
126*2dc23587SToomas Soome 		return (BAM_ERROR);
127*2dc23587SToomas Soome 	}
128*2dc23587SToomas Soome 
129*2dc23587SToomas Soome 	/* Get slot count */
130*2dc23587SToomas Soome 	rv = C_GetSlotList(0, NULL, &slotcount);
131*2dc23587SToomas Soome 	if (rv != CKR_OK || slotcount == 0) {
132*2dc23587SToomas Soome 		bam_print(gettext(
133*2dc23587SToomas Soome 		    "failed to find any cryptographic provider: %s\n"),
134*2dc23587SToomas Soome 		    pkcs11_strerror(rv));
135*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
136*2dc23587SToomas Soome 		goto cleanup;
137*2dc23587SToomas Soome 	}
138*2dc23587SToomas Soome 
139*2dc23587SToomas Soome 	/* Found at least one slot, allocate memory for slot list */
140*2dc23587SToomas Soome 	pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID));
141*2dc23587SToomas Soome 	if (pSlotList == NULL) {
142*2dc23587SToomas Soome 		bam_print(gettext("out of memory\n"));
143*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
144*2dc23587SToomas Soome 		goto cleanup;
145*2dc23587SToomas Soome 	}
146*2dc23587SToomas Soome 
147*2dc23587SToomas Soome 	/* Get the list of slots */
148*2dc23587SToomas Soome 	if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) {
149*2dc23587SToomas Soome 		bam_print(gettext(
150*2dc23587SToomas Soome 		    "failed to find any cryptographic provider; "
151*2dc23587SToomas Soome 		    "please check with your system administrator: %s\n"),
152*2dc23587SToomas Soome 		    pkcs11_strerror(rv));
153*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
154*2dc23587SToomas Soome 		goto cleanup;
155*2dc23587SToomas Soome 	}
156*2dc23587SToomas Soome 
157*2dc23587SToomas Soome 	/* Find a slot with matching mechanism */
158*2dc23587SToomas Soome 	for (i = 0; i < slotcount; i++) {
159*2dc23587SToomas Soome 		slotID = pSlotList[i];
160*2dc23587SToomas Soome 		rv = C_GetMechanismInfo(slotID, mech_type, &info);
161*2dc23587SToomas Soome 		if (rv != CKR_OK) {
162*2dc23587SToomas Soome 			continue; /* to the next slot */
163*2dc23587SToomas Soome 		} else {
164*2dc23587SToomas Soome 			if (info.flags & CKF_DIGEST)
165*2dc23587SToomas Soome 				break;
166*2dc23587SToomas Soome 		}
167*2dc23587SToomas Soome 	}
168*2dc23587SToomas Soome 
169*2dc23587SToomas Soome 	/* Show error if no matching mechanism found */
170*2dc23587SToomas Soome 	if (i == slotcount) {
171*2dc23587SToomas Soome 		bam_print(gettext("no cryptographic provider was "
172*2dc23587SToomas Soome 		    "found for sha1\n"));
173*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
174*2dc23587SToomas Soome 		goto cleanup;
175*2dc23587SToomas Soome 	}
176*2dc23587SToomas Soome 
177*2dc23587SToomas Soome 	/* Mechanism is supported. Go ahead & open a session */
178*2dc23587SToomas Soome 	rv = C_OpenSession(slotID, CKF_SERIAL_SESSION,
179*2dc23587SToomas Soome 	    NULL, NULL, &hSession);
180*2dc23587SToomas Soome 
181*2dc23587SToomas Soome 	if (rv != CKR_OK) {
182*2dc23587SToomas Soome 		bam_print(gettext("can not open PKCS#11 session: %s\n"),
183*2dc23587SToomas Soome 		    pkcs11_strerror(rv));
184*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
185*2dc23587SToomas Soome 		goto cleanup;
186*2dc23587SToomas Soome 	}
187*2dc23587SToomas Soome 
188*2dc23587SToomas Soome 	/* Allocate a buffer to store result. */
189*2dc23587SToomas Soome 	resultlen = RESULTLEN;
190*2dc23587SToomas Soome 	if ((resultbuf = malloc(resultlen)) == NULL) {
191*2dc23587SToomas Soome 		bam_print(gettext("out of memory\n"));
192*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
193*2dc23587SToomas Soome 		goto cleanup;
194*2dc23587SToomas Soome 	}
195*2dc23587SToomas Soome 
196*2dc23587SToomas Soome 	mech.mechanism = mech_type;
197*2dc23587SToomas Soome 	mech.pParameter = NULL;
198*2dc23587SToomas Soome 	mech.ulParameterLen = 0;
199*2dc23587SToomas Soome 	exitcode = BAM_SUCCESS;
200*2dc23587SToomas Soome 
201*2dc23587SToomas Soome 	if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) {
202*2dc23587SToomas Soome 		bam_print(gettext("can not open input file %s\n"), filename);
203*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
204*2dc23587SToomas Soome 		goto cleanup;
205*2dc23587SToomas Soome 	}
206*2dc23587SToomas Soome 
207*2dc23587SToomas Soome 	rv = do_digest(hSession, &mech, fd, &resultbuf, &resultlen);
208*2dc23587SToomas Soome 
209*2dc23587SToomas Soome 	if (rv != CKR_OK) {
210*2dc23587SToomas Soome 		bam_print(gettext("crypto operation failed for "
211*2dc23587SToomas Soome 		    "file %s: %s\n"), filename, pkcs11_strerror(rv));
212*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
213*2dc23587SToomas Soome 		goto cleanup;
214*2dc23587SToomas Soome 	}
215*2dc23587SToomas Soome 
216*2dc23587SToomas Soome 	/* Allocate a buffer to store result string */
217*2dc23587SToomas Soome 	resultstrlen = 2 * resultlen + 1;
218*2dc23587SToomas Soome 	if ((resultstr = malloc(resultstrlen)) == NULL) {
219*2dc23587SToomas Soome 		bam_print(gettext("out of memory\n"));
220*2dc23587SToomas Soome 		exitcode = BAM_ERROR;
221*2dc23587SToomas Soome 		goto cleanup;
222*2dc23587SToomas Soome 	}
223*2dc23587SToomas Soome 
224*2dc23587SToomas Soome 	tohexstr(resultbuf, resultlen, resultstr, resultstrlen);
225*2dc23587SToomas Soome 
226*2dc23587SToomas Soome 	(void) close(fd);
227*2dc23587SToomas Soome cleanup:
228*2dc23587SToomas Soome 	if (exitcode == BAM_ERROR) {
229*2dc23587SToomas Soome 		free(resultstr);
230*2dc23587SToomas Soome 		resultstr = NULL;
231*2dc23587SToomas Soome 	}
232*2dc23587SToomas Soome 
233*2dc23587SToomas Soome 	free(resultbuf);
234*2dc23587SToomas Soome 	free(pSlotList);
235*2dc23587SToomas Soome 
236*2dc23587SToomas Soome 	if (hSession != CK_INVALID_HANDLE)
237*2dc23587SToomas Soome 		(void) C_CloseSession(hSession);
238*2dc23587SToomas Soome 
239*2dc23587SToomas Soome 	(void) C_Finalize(NULL);
240*2dc23587SToomas Soome 
241*2dc23587SToomas Soome 	*result = resultstr;
242*2dc23587SToomas Soome 	return (exitcode);
243*2dc23587SToomas Soome }
244