xref: /illumos-gate/usr/src/lib/libelfsign/common/elfcertlib.c (revision 6d02032db7b674f185405d42cc8bf10a46a9ab3a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <limits.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <dirent.h>
33 #include <strings.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <sys/mman.h>
38 #include <md5.h>
39 #include <pthread.h>
40 
41 #include <cryptoutil.h>
42 
43 #include <kmfapi.h>
44 #include <sys/crypto/elfsign.h>
45 #include <libelfsign.h>
46 
47 #include <synch.h>
48 
49 const char _PATH_ELFSIGN_CRYPTO_CERTS[] = CRYPTO_CERTS_DIR;
50 const char _PATH_ELFSIGN_ETC_CERTS[] = ETC_CERTS_DIR;
51 
52 /*
53  * The CACERT and OBJCACERT are the Cryptographic Trust Anchors
54  * for the Solaris Cryptographic Framework.
55  *
56  * The SECACERT is the Signed Execution Trust Anchor that the
57  * Cryptographic Framework uses for FIPS-140 validation of non-crypto
58  * binaries
59  */
60 static const char _PATH_CRYPTO_CACERT[] = CRYPTO_CERTS_DIR "/CA";
61 static const char _PATH_CRYPTO_OBJCACERT[] = CRYPTO_CERTS_DIR "/SUNWObjectCA";
62 static const char _PATH_CRYPTO_SECACERT[] = ETC_CERTS_DIR "/SUNWSolarisCA";
63 static ELFCert_t CACERT = NULL;
64 static ELFCert_t OBJCACERT = NULL;
65 static ELFCert_t SECACERT = NULL;
66 static pthread_mutex_t ca_mutex = PTHREAD_MUTEX_INITIALIZER;
67 
68 static void elfcertlib_freecert(ELFsign_t, ELFCert_t);
69 static ELFCert_t elfcertlib_allocatecert(void);
70 
71 /*
72  * elfcertlib_verifycert - Verify the Cert with a Trust Anchor
73  *
74  * IN	ess		- elfsign context structure
75  *	cert
76  * OUT	NONE
77  * RETURN	TRUE/FALSE
78  *
79  * We first setup the Trust Anchor (CA and SUNWObjectCA) certs
80  * if it hasn't been done already.  We verify that the files on disk
81  * are those we expected.
82  *
83  * We then verify the given cert using the publickey of a TA.
84  * If the passed in cert is a TA or it has been verified already we
85  * short cut and return TRUE without futher validation.
86  */
87 /*ARGSUSED*/
88 boolean_t
89 elfcertlib_verifycert(ELFsign_t ess, ELFCert_t cert)
90 {
91 	KMF_ATTRIBUTE	attrlist[8];
92 	int		numattr;
93 
94 	KMF_RETURN rv;
95 	if ((cert->c_verified == E_OK) || (cert->c_verified == E_IS_TA)) {
96 		return (B_TRUE);
97 	}
98 
99 	(void) pthread_mutex_lock(&ca_mutex);
100 	if (CACERT == NULL) {
101 		(void) elfcertlib_getcert(ess, (char *)_PATH_CRYPTO_CACERT,
102 		    NULL, &CACERT, ES_GET);
103 	}
104 
105 	if (OBJCACERT == NULL) {
106 		(void) elfcertlib_getcert(ess, (char *)_PATH_CRYPTO_OBJCACERT,
107 		    NULL, &OBJCACERT, ES_GET);
108 	}
109 
110 	if (SECACERT == NULL) {
111 		(void) elfcertlib_getcert(ess,
112 		    (char *)_PATH_CRYPTO_SECACERT, NULL, &SECACERT,
113 		    ES_GET_FIPS140);
114 	}
115 
116 	(void) pthread_mutex_unlock(&ca_mutex);
117 
118 	if (CACERT != NULL) {
119 		numattr = 0;
120 		kmf_set_attr_at_index(attrlist, numattr++,
121 		    KMF_CERT_DATA_ATTR, &cert->c_cert.certificate,
122 		    sizeof (KMF_DATA));
123 		kmf_set_attr_at_index(attrlist, numattr++,
124 		    KMF_SIGNER_CERT_DATA_ATTR, &CACERT->c_cert.certificate,
125 		    sizeof (KMF_DATA));
126 
127 		rv = kmf_verify_cert(ess->es_kmfhandle, numattr, attrlist);
128 		if (rv == KMF_OK) {
129 			if (ess->es_certCAcallback != NULL)
130 				(ess->es_certvercallback)(ess->es_callbackctx,
131 				    cert, CACERT);
132 			cert->c_verified = E_OK;
133 			return (B_TRUE);
134 		}
135 	}
136 
137 	if (OBJCACERT != NULL) {
138 		numattr = 0;
139 		kmf_set_attr_at_index(attrlist, numattr++,
140 		    KMF_CERT_DATA_ATTR, &cert->c_cert.certificate,
141 		    sizeof (KMF_DATA));
142 		kmf_set_attr_at_index(attrlist, numattr++,
143 		    KMF_SIGNER_CERT_DATA_ATTR, &OBJCACERT->c_cert.certificate,
144 		    sizeof (KMF_DATA));
145 
146 		rv = kmf_verify_cert(ess->es_kmfhandle, numattr, attrlist);
147 		if (rv == KMF_OK) {
148 			if (ess->es_certCAcallback != NULL)
149 				(ess->es_certvercallback)(ess->es_callbackctx,
150 				    cert, OBJCACERT);
151 			cert->c_verified = E_OK;
152 			return (B_TRUE);
153 		}
154 	}
155 
156 	if (SECACERT != NULL) {
157 		numattr = 0;
158 		kmf_set_attr_at_index(attrlist, numattr++,
159 		    KMF_CERT_DATA_ATTR, &cert->c_cert.certificate,
160 		    sizeof (KMF_DATA));
161 		kmf_set_attr_at_index(attrlist, numattr++,
162 		    KMF_SIGNER_CERT_DATA_ATTR, &SECACERT->c_cert.certificate,
163 		    sizeof (KMF_DATA));
164 
165 		rv = kmf_verify_cert(ess->es_kmfhandle, numattr, attrlist);
166 		if (rv == KMF_OK) {
167 			if (ess->es_certCAcallback != NULL)
168 				(ess->es_certvercallback)(ess->es_callbackctx,
169 				    cert, SECACERT);
170 			cert->c_verified = E_OK;
171 			return (B_TRUE);
172 		}
173 	}
174 
175 	return (B_FALSE);
176 }
177 
178 /*
179  * elfcertlib_getcert - Get the certificate for signer_DN
180  *
181  * IN	ess		- elfsign context structure
182  *	cert_pathname	- path to cert (May be NULL)
183  *	signer_DN	- The DN we are looking for (May be NULL)
184  *      action		- indicates crypto verification call
185  * OUT  certp		- allocated/loaded ELFCert_t
186  *
187  * If the cert_pathname is passed use it and don't search.
188  * Otherwise, go looking in certificate directories
189  */
190 boolean_t
191 elfcertlib_getcert(ELFsign_t ess, char *cert_pathname,
192     char *signer_DN, ELFCert_t *certp, enum ES_ACTION action)
193 {
194 	KMF_RETURN rv;
195 	ELFCert_t	cert = NULL;
196 	KMF_X509_DER_CERT certbuf[2];
197 	uint32_t ncerts;
198 	boolean_t ret = B_FALSE;
199 	char	*pathlist[3], **plp;
200 
201 	cryptodebug("elfcertlib_getcert: path=%s, DN=%s",
202 	    cert_pathname ? cert_pathname : "-none-",
203 	    signer_DN ? signer_DN : "-none-");
204 	*certp = NULL;
205 	if (cert_pathname == NULL && signer_DN == NULL) {
206 		cryptodebug("elfcertlib_getcert: lack of specificity");
207 		return (ret);
208 	}
209 
210 	plp = pathlist;
211 	if (cert_pathname != NULL) {
212 		/* look in the specified object */
213 		*plp++ = cert_pathname;
214 	} else {
215 		/* look in the certificate directories */
216 		*plp++ = (char *)_PATH_ELFSIGN_CRYPTO_CERTS;
217 		/*
218 		 * crypto verifications don't search beyond
219 		 * _PATH_ELFSIGN_CRYPTO_CERTS
220 		 */
221 		if (action != ES_GET_CRYPTO)
222 			*plp++ = (char *)_PATH_ELFSIGN_ETC_CERTS;
223 	}
224 	*plp = NULL;
225 
226 	if ((cert = elfcertlib_allocatecert()) == NULL) {
227 		return (ret);
228 	}
229 
230 	for (plp = pathlist; *plp; plp++) {
231 		KMF_ATTRIBUTE	attrlist[8];
232 		KMF_KEYSTORE_TYPE	kstype;
233 		KMF_CERT_VALIDITY	certvalidity;
234 		int		numattr;
235 
236 		kstype = KMF_KEYSTORE_OPENSSL;
237 		certvalidity = KMF_ALL_CERTS;
238 		ncerts = 2;
239 
240 		numattr = 0;
241 		kmf_set_attr_at_index(attrlist, numattr++,
242 		    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
243 		kmf_set_attr_at_index(attrlist, numattr++,
244 		    KMF_X509_DER_CERT_ATTR, certbuf,
245 		    sizeof (KMF_X509_DER_CERT));
246 		kmf_set_attr_at_index(attrlist, numattr++,
247 		    KMF_COUNT_ATTR, &ncerts, sizeof (uint32_t));
248 		if (signer_DN != NULL) {
249 			kmf_set_attr_at_index(attrlist, numattr++,
250 			    KMF_SUBJECT_NAME_ATTR, signer_DN,
251 			    strlen(signer_DN));
252 		}
253 		kmf_set_attr_at_index(attrlist, numattr++,
254 		    KMF_CERT_VALIDITY_ATTR, &certvalidity,
255 		    sizeof (KMF_CERT_VALIDITY));
256 		kmf_set_attr_at_index(attrlist, numattr++,
257 		    KMF_CERT_FILENAME_ATTR, *plp, strlen (*plp));
258 
259 		rv = kmf_find_cert(ess->es_kmfhandle, numattr, attrlist);
260 
261 		if (rv != KMF_OK)
262 			continue;
263 		/* found one */
264 		cert->c_cert = certbuf[0];
265 		if (ncerts > 1) {
266 			/* release any extras */
267 			kmf_free_kmf_cert(ess->es_kmfhandle, &certbuf[1]);
268 			if (signer_DN == NULL) {
269 				/* There can be only one */
270 				cryptodebug("elfcertlib_getcert: "
271 				    "too many certificates found in %s",
272 				    cert_pathname);
273 				goto cleanup;
274 			}
275 		}
276 		/* cache subject and issuer */
277 		rv = kmf_get_cert_subject_str(ess->es_kmfhandle,
278 		    &cert->c_cert.certificate, &cert->c_subject);
279 		if (rv != KMF_OK)
280 			goto cleanup;
281 
282 		rv = kmf_get_cert_issuer_str(ess->es_kmfhandle,
283 		    &cert->c_cert.certificate, &cert->c_issuer);
284 		if (rv != KMF_OK)
285 			goto cleanup;
286 		break;
287 	}
288 	if (*plp == NULL) {
289 		cryptodebug("elfcertlib_getcert: no certificate found");
290 		goto cleanup;
291 	}
292 
293 	cert->c_verified = E_UNCHECKED;
294 
295 	/*
296 	 * If the cert we are loading is the trust anchor (ie the CA) then
297 	 * we mark it as such in cert.  This is so that we don't attempt
298 	 * to verify it later.  The CA is always implicitly verified.
299 	 */
300 	if (cert_pathname != NULL && (
301 	    strcmp(cert_pathname, _PATH_CRYPTO_CACERT) == 0 ||
302 	    strcmp(cert_pathname, _PATH_CRYPTO_OBJCACERT) == 0 ||
303 	    strcmp(cert_pathname, _PATH_CRYPTO_SECACERT) == 0)) {
304 		if (ess->es_certCAcallback != NULL)
305 			(ess->es_certCAcallback)(ess->es_callbackctx, cert,
306 			    cert_pathname);
307 		cert->c_verified = E_IS_TA;
308 	}
309 
310 	ret = B_TRUE;
311 
312 cleanup:
313 	if (ret) {
314 		*certp = cert;
315 	} else {
316 		if (cert != NULL)
317 			elfcertlib_freecert(ess, cert);
318 		if (signer_DN != NULL)
319 			cryptoerror(LOG_ERR, "unable to find a certificate "
320 			    "for DN: %s", signer_DN);
321 		else
322 			cryptoerror(LOG_ERR, "unable to load certificate "
323 			    "from %s", cert_pathname);
324 	}
325 	return (ret);
326 }
327 
328 /*
329  * elfcertlib_loadprivatekey - Load the private key from path
330  *
331  * IN	ess		- elfsign context structure
332  *	cert
333  *	pathname
334  * OUT	cert
335  * RETURNS	TRUE/FALSE
336  */
337 boolean_t
338 elfcertlib_loadprivatekey(ELFsign_t ess, ELFCert_t cert, const char *pathname)
339 {
340 	KMF_RETURN	rv = KMF_OK;
341 	KMF_KEY_HANDLE	keybuf[2];
342 	KMF_ATTRIBUTE	attrlist[16];
343 	uint32_t	nkeys;
344 	KMF_KEYSTORE_TYPE	kstype;
345 	KMF_KEY_ALG	keytype;
346 	KMF_KEY_CLASS	keyclass;
347 	KMF_ENCODE_FORMAT	format;
348 	int		numattr;
349 
350 	kstype = KMF_KEYSTORE_OPENSSL;
351 	nkeys = 2;
352 	keytype = KMF_KEYALG_NONE;
353 	keyclass = KMF_ASYM_PRI;
354 	format = KMF_FORMAT_UNDEF;
355 
356 	numattr = 0;
357 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYSTORE_TYPE_ATTR,
358 	    &kstype, sizeof (kstype));
359 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEY_HANDLE_ATTR,
360 	    keybuf, sizeof (KMF_KEY_HANDLE));
361 	kmf_set_attr_at_index(attrlist, numattr++, KMF_COUNT_ATTR,
362 	    &nkeys, sizeof (uint32_t));
363 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYALG_ATTR,
364 	    &keytype, sizeof (keytype));
365 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYCLASS_ATTR,
366 	    &keyclass, sizeof (keyclass));
367 	kmf_set_attr_at_index(attrlist, numattr++, KMF_ENCODE_FORMAT_ATTR,
368 	    &format, sizeof (format));
369 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEY_FILENAME_ATTR,
370 	    (char *)pathname, strlen(pathname));
371 
372 	rv = kmf_find_key(ess->es_kmfhandle, numattr, attrlist);
373 	if (rv != KMF_OK)
374 		return (B_FALSE);
375 	if (nkeys != 1) {
376 		/* lack of specificity */
377 		cryptodebug("found %d keys at %s", nkeys, pathname);
378 		return (B_FALSE);
379 	}
380 	cert->c_privatekey = keybuf[0];
381 	cryptodebug("key %s loaded", pathname);
382 	return (B_TRUE);
383 }
384 
385 /*
386  * elfcertlib_loadtokenkey - Load the private key from token
387  *
388  * IN	ess		- elfsign context structure
389  *	cert
390  *	token_label
391  *	pin
392  * OUT	cert
393  * RETURNS	TRUE/FALSE
394  */
395 boolean_t
396 elfcertlib_loadtokenkey(ELFsign_t ess, ELFCert_t cert,
397     const char *token_label, const char *pin)
398 {
399 	KMF_RETURN	rv;
400 	char		*idstr = NULL;
401 	char		*kmferr;
402 	KMF_ATTRIBUTE	attrlist[16];
403 	uint32_t	nkeys;
404 	KMF_KEYSTORE_TYPE	kstype;
405 	KMF_KEY_ALG	keytype;
406 	KMF_KEY_CLASS	keyclass;
407 	KMF_ENCODE_FORMAT	format;
408 	KMF_CREDENTIAL	pincred;
409 	boolean_t	tokenbool, privatebool;
410 	int		numattr;
411 
412 	/*
413 	 * We will search for the key based on the ID attribute
414 	 * which was added when the key was created.  ID is
415 	 * a SHA-1 hash of the public modulus shared by the
416 	 * key and the certificate.
417 	 */
418 	rv = kmf_get_cert_id_str(&cert->c_cert.certificate, &idstr);
419 	if (rv != KMF_OK) {
420 		(void) kmf_get_kmf_error_str(rv, &kmferr);
421 		cryptodebug("Error getting ID from cert: %s\n",
422 		    (kmferr ? kmferr : "Unrecognized KMF error"));
423 		free(kmferr);
424 		return (B_FALSE);
425 	}
426 
427 	kstype = KMF_KEYSTORE_PK11TOKEN;
428 	nkeys = 1;
429 	keytype = KMF_KEYALG_NONE;
430 	keyclass = KMF_ASYM_PRI;
431 	format = KMF_FORMAT_UNDEF;
432 	pincred.cred = (char *)pin;
433 	pincred.credlen = strlen(pin);
434 	tokenbool = B_FALSE;
435 	privatebool = B_TRUE;
436 
437 	numattr = 0;
438 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYSTORE_TYPE_ATTR,
439 	    &kstype, sizeof (kstype));
440 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEY_HANDLE_ATTR,
441 	    &cert->c_privatekey, sizeof (KMF_KEY_HANDLE));
442 	kmf_set_attr_at_index(attrlist, numattr++, KMF_COUNT_ATTR,
443 	    &nkeys, sizeof (uint32_t));
444 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYALG_ATTR,
445 	    &keytype, sizeof (keytype));
446 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYCLASS_ATTR,
447 	    &keyclass, sizeof (keyclass));
448 	kmf_set_attr_at_index(attrlist, numattr++, KMF_ENCODE_FORMAT_ATTR,
449 	    &format, sizeof (format));
450 	kmf_set_attr_at_index(attrlist, numattr++, KMF_IDSTR_ATTR,
451 	    idstr, strlen(idstr));
452 	kmf_set_attr_at_index(attrlist, numattr++, KMF_CREDENTIAL_ATTR,
453 	    &pincred, sizeof (KMF_CREDENTIAL));
454 	kmf_set_attr_at_index(attrlist, numattr++, KMF_TOKEN_BOOL_ATTR,
455 	    &tokenbool, sizeof (tokenbool));
456 	kmf_set_attr_at_index(attrlist, numattr++, KMF_PRIVATE_BOOL_ATTR,
457 	    &privatebool, sizeof (privatebool));
458 
459 	rv = kmf_find_key(ess->es_kmfhandle, numattr, attrlist);
460 	free(idstr);
461 	if (rv != KMF_OK) {
462 		(void) kmf_get_kmf_error_str(rv, &kmferr);
463 		cryptodebug("Error finding private key: %s\n",
464 		    (kmferr ? kmferr : "Unrecognized KMF error"));
465 		free(kmferr);
466 		return (B_FALSE);
467 	}
468 	if (nkeys != 1) {
469 		cryptodebug("Error finding private key: No key found\n");
470 		return (B_FALSE);
471 	}
472 	cryptodebug("key found in %s", token_label);
473 	cryptodebug("elfcertlib_loadprivatekey = 0x%.8X",
474 	    &cert->c_privatekey);
475 
476 	return (B_TRUE);
477 }
478 
479 static const CK_BYTE MD5_DER_PREFIX[] = {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
480 	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10};
481 
482 /*
483  * elfcertlib_sign - sign the given DATA using the privatekey in cert
484  *
485  * IN	ess		- elfsign context structure
486  *	cert
487  *	data
488  *	data_len
489  * OUT	sig	- must be big enough to hold the signature of data
490  *		  Caller must allocate
491  *	sig_len	- actual length used; 0 on failure.
492  * RETURNS	TRUE/FALSE
493  */
494 /*ARGSUSED*/
495 boolean_t
496 elfcertlib_sign(ELFsign_t ess, ELFCert_t cert,
497 	const uchar_t *data, size_t data_len,
498 	uchar_t *sig, size_t *sig_len)
499 {
500 	KMF_RETURN	ret;
501 	KMF_DATA	tobesigned;
502 	KMF_DATA	signature;
503 	uchar_t		der_data[sizeof (MD5_DER_PREFIX) + MD5_DIGEST_LENGTH];
504 	KMF_ATTRIBUTE	attrlist[8];
505 	int		numattr;
506 
507 	if (ess->es_version <= FILESIG_VERSION2) {
508 		/* compatibility: take MD5 hash of SHA1 hash */
509 		size_t	derlen = MD5_DIGEST_LENGTH;
510 		MD5_CTX ctx;
511 
512 		/*
513 		 * first: digest using software-based methods, don't
514 		 * rely on the token for hashing.
515 		 */
516 		MD5Init(&ctx);
517 		MD5Update(&ctx, data, data_len);
518 		MD5Final(&der_data[sizeof (MD5_DER_PREFIX)], &ctx);
519 
520 		/*
521 		 * second: insert prefix
522 		 */
523 		(void) memcpy(der_data, MD5_DER_PREFIX,
524 		    sizeof (MD5_DER_PREFIX));
525 		/*
526 		 * prepare to sign the local buffer
527 		 */
528 		tobesigned.Data = (uchar_t *)der_data;
529 		tobesigned.Length = sizeof (MD5_DER_PREFIX) + derlen;
530 	} else {
531 		tobesigned.Data = (uchar_t *)data;
532 		tobesigned.Length = data_len;
533 	}
534 
535 	signature.Data = (uchar_t *)sig;
536 	signature.Length = *sig_len;
537 
538 	numattr = 0;
539 	kmf_set_attr_at_index(attrlist, numattr++,
540 	    KMF_KEYSTORE_TYPE_ATTR, &(cert->c_privatekey.kstype),
541 	    sizeof (KMF_KEYSTORE_TYPE));
542 	kmf_set_attr_at_index(attrlist, numattr++,
543 	    KMF_KEY_HANDLE_ATTR, &cert->c_privatekey, sizeof (KMF_KEY_HANDLE));
544 	kmf_set_attr_at_index(attrlist, numattr++,
545 	    KMF_OID_ATTR, (KMF_OID *)&KMFOID_RSA, sizeof (KMF_OID));
546 	kmf_set_attr_at_index(attrlist, numattr++,
547 	    KMF_DATA_ATTR, &tobesigned, sizeof (KMF_DATA));
548 	kmf_set_attr_at_index(attrlist, numattr++,
549 	    KMF_OUT_DATA_ATTR, &signature, sizeof (KMF_DATA));
550 
551 	ret = kmf_sign_data(ess->es_kmfhandle, numattr, attrlist);
552 
553 	if (ret != KMF_OK) {
554 		char	*kmferr;
555 
556 		(void) kmf_get_kmf_error_str(ret, &kmferr);
557 		cryptodebug("Error signing data: %s\n",
558 		    (kmferr ? kmferr : "Unrecognized KMF error"));
559 		free(kmferr);
560 		*sig_len = 0;
561 		return (B_FALSE);
562 	}
563 	*sig_len = signature.Length;
564 	return (B_TRUE);
565 }
566 
567 /*
568  * elfcertlib_verifysig - verify the given DATA using the public key in cert
569  *
570  * IN	ess		- elfsign context structure
571  *	cert
572  *	signature
573  *	sig_len
574  *	data
575  *	data_len
576  * OUT	N/A
577  * RETURNS	TRUE/FALSE
578  */
579 boolean_t
580 elfcertlib_verifysig(ELFsign_t ess, ELFCert_t cert,
581 	const uchar_t *signature, size_t sig_len,
582 	const uchar_t *data, size_t data_len)
583 {
584 	KMF_RETURN	rv;
585 	KMF_DATA	indata;
586 	KMF_DATA	insig;
587 	KMF_ALGORITHM_INDEX algid;
588 	KMF_ATTRIBUTE	attrlist[8];
589 	KMF_KEYSTORE_TYPE	kstype;
590 	int		numattr;
591 
592 	indata.Data = (uchar_t *)data;
593 	indata.Length = data_len;
594 	insig.Data = (uchar_t *)signature;
595 	insig.Length = sig_len;
596 
597 	if (ess->es_version <= FILESIG_VERSION2)
598 		algid = KMF_ALGID_MD5WithRSA;
599 	else
600 		algid = KMF_ALGID_RSA;
601 
602 	/*
603 	 * We tell KMF to use the PKCS11 verification APIs
604 	 * here to prevent the use of OpenSSL and to keep
605 	 * all validation within the FIPS-140 boundary for
606 	 * the Cryptographic Framework.
607 	 */
608 	kstype = KMF_KEYSTORE_PK11TOKEN;
609 
610 	numattr = 0;
611 	kmf_set_attr_at_index(attrlist, numattr++, KMF_KEYSTORE_TYPE_ATTR,
612 	    &kstype,  sizeof (kstype));
613 	kmf_set_attr_at_index(attrlist, numattr++, KMF_DATA_ATTR,
614 	    &indata, sizeof (KMF_DATA));
615 	kmf_set_attr_at_index(attrlist, numattr++, KMF_IN_SIGN_ATTR,
616 	    &insig, sizeof (KMF_DATA));
617 	kmf_set_attr_at_index(attrlist, numattr++, KMF_SIGNER_CERT_DATA_ATTR,
618 	    (KMF_DATA *)(&cert->c_cert.certificate), sizeof (KMF_DATA));
619 	kmf_set_attr_at_index(attrlist, numattr++, KMF_ALGORITHM_INDEX_ATTR,
620 	    &algid, sizeof (algid));
621 
622 	rv = kmf_verify_data(ess->es_kmfhandle, numattr, attrlist);
623 
624 	return ((rv == KMF_OK));
625 }
626 
627 /*
628  * elfcertlib_getdn
629  *
630  * IN	cert
631  * OUT	NONE
632  * RETURN 	dn or NULL
633  */
634 char *
635 elfcertlib_getdn(ELFCert_t cert)
636 {
637 	cryptodebug("elfcertlib_getdn");
638 
639 	return (cert->c_subject);
640 }
641 
642 /*
643  * elfcertlib_getissuer
644  *
645  * IN	cert
646  * OUT	NONE
647  * RETURN 	dn or NULL
648  */
649 char *
650 elfcertlib_getissuer(ELFCert_t cert)
651 {
652 	cryptodebug("elfcertlib_issuer");
653 
654 	return (cert->c_issuer);
655 }
656 
657 boolean_t
658 elfcertlib_init(ELFsign_t ess)
659 {
660 	boolean_t rc = B_TRUE;
661 	KMF_RETURN rv;
662 	if (ess->es_kmfhandle == NULL) {
663 		rv = kmf_initialize(&ess->es_kmfhandle, NULL, NULL);
664 		if (rv != KMF_OK) {
665 			cryptoerror(LOG_ERR,
666 			    "unable to initialize KMF library");
667 			rc = B_FALSE;
668 		}
669 	}
670 	return (rc);
671 }
672 
673 void
674 elfcertlib_fini(ELFsign_t ess)
675 {
676 	(void) kmf_finalize(ess->es_kmfhandle);
677 }
678 
679 /*
680  * set the token device
681  */
682 boolean_t
683 elfcertlib_settoken(ELFsign_t ess, char *token)
684 {
685 	boolean_t	rc = B_TRUE;
686 	KMF_RETURN	rv;
687 	KMF_ATTRIBUTE	attrlist[8];
688 	KMF_KEYSTORE_TYPE	kstype;
689 	boolean_t	readonly;
690 	int	numattr;
691 
692 	kstype = KMF_KEYSTORE_PK11TOKEN;
693 	readonly = B_TRUE;
694 
695 	numattr = 0;
696 	kmf_set_attr_at_index(attrlist, numattr++,
697 	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
698 	kmf_set_attr_at_index(attrlist, numattr++,
699 	    KMF_TOKEN_LABEL_ATTR, token, strlen(token));
700 	kmf_set_attr_at_index(attrlist, numattr++,
701 	    KMF_READONLY_ATTR, &readonly, sizeof (readonly));
702 
703 	rv = kmf_configure_keystore(ess->es_kmfhandle, numattr, attrlist);
704 	if (rv != KMF_OK) {
705 		cryptoerror(LOG_ERR, "unable to select token\n");
706 		rc = B_FALSE;
707 	}
708 
709 	return (rc);
710 }
711 
712 /*
713  * set the certificate CA identification callback
714  */
715 void
716 elfcertlib_setcertCAcallback(ELFsign_t ess,
717     void (*cb)(void *, ELFCert_t, char *))
718 {
719 	ess->es_certCAcallback = cb;
720 }
721 
722 /*
723  * set the certificate verification callback
724  */
725 void
726 elfcertlib_setcertvercallback(ELFsign_t ess,
727     void (*cb)(void *, ELFCert_t, ELFCert_t))
728 {
729 	ess->es_certvercallback = cb;
730 }
731 
732 
733 /*
734  * elfcertlib_releasecert - release a cert
735  *
736  * IN cert
737  * OUT cert
738  * RETURN	N/A
739  *
740  */
741 void
742 elfcertlib_releasecert(ELFsign_t ess, ELFCert_t cert)
743 {
744 	elfcertlib_freecert(ess, cert);
745 }
746 
747 /*
748  * elfcertlib_allocatecert - create a new ELFCert_t
749  *
750  * IN N/A
751  * OUT	N/A
752  * RETURN 	ELFCert_t, NULL on failure.
753  */
754 static ELFCert_t
755 elfcertlib_allocatecert(void)
756 {
757 	ELFCert_t cert = NULL;
758 
759 	cert = malloc(sizeof (struct ELFCert_s));
760 	if (cert == NULL) {
761 		cryptoerror(LOG_ERR,
762 		    "elfcertlib_allocatecert: malloc failed %s",
763 		    strerror(errno));
764 		return (NULL);
765 	}
766 	(void) memset(cert, 0, sizeof (struct ELFCert_s));
767 	cert->c_verified = E_UNCHECKED;
768 	cert->c_subject = NULL;
769 	cert->c_issuer = NULL;
770 	return (cert);
771 }
772 
773 /*
774  * elfcertlib_freecert - freeup the memory of a cert
775  *
776  * IN cert
777  * OUT cert
778  * RETURN	N/A
779  *
780  */
781 static void
782 elfcertlib_freecert(ELFsign_t ess, ELFCert_t cert)
783 {
784 	if (cert == NULL)
785 		return;
786 
787 	free(cert->c_subject);
788 	free(cert->c_issuer);
789 
790 	kmf_free_kmf_cert(ess->es_kmfhandle, &cert->c_cert);
791 	kmf_free_kmf_key(ess->es_kmfhandle, &cert->c_privatekey);
792 
793 	free(cert);
794 }
795