17934SMark.Phalan@Sun.COM /*
27934SMark.Phalan@Sun.COM  * COPYRIGHT (C) 2006,2007
37934SMark.Phalan@Sun.COM  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
47934SMark.Phalan@Sun.COM  * ALL RIGHTS RESERVED
57934SMark.Phalan@Sun.COM  *
67934SMark.Phalan@Sun.COM  * Permission is granted to use, copy, create derivative works
77934SMark.Phalan@Sun.COM  * and redistribute this software and such derivative works
87934SMark.Phalan@Sun.COM  * for any purpose, so long as the name of The University of
97934SMark.Phalan@Sun.COM  * Michigan is not used in any advertising or publicity
107934SMark.Phalan@Sun.COM  * pertaining to the use of distribution of this software
117934SMark.Phalan@Sun.COM  * without specific, written prior authorization.  If the
127934SMark.Phalan@Sun.COM  * above copyright notice or any other identification of the
137934SMark.Phalan@Sun.COM  * University of Michigan is included in any copy of any
147934SMark.Phalan@Sun.COM  * portion of this software, then the disclaimer below must
157934SMark.Phalan@Sun.COM  * also be included.
167934SMark.Phalan@Sun.COM  *
177934SMark.Phalan@Sun.COM  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
187934SMark.Phalan@Sun.COM  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
197934SMark.Phalan@Sun.COM  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
207934SMark.Phalan@Sun.COM  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
217934SMark.Phalan@Sun.COM  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
227934SMark.Phalan@Sun.COM  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
237934SMark.Phalan@Sun.COM  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
247934SMark.Phalan@Sun.COM  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
257934SMark.Phalan@Sun.COM  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
267934SMark.Phalan@Sun.COM  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
277934SMark.Phalan@Sun.COM  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
287934SMark.Phalan@Sun.COM  * SUCH DAMAGES.
297934SMark.Phalan@Sun.COM  */
307934SMark.Phalan@Sun.COM 
317934SMark.Phalan@Sun.COM /*
3212359SMark.Phalan@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
337934SMark.Phalan@Sun.COM  */
347934SMark.Phalan@Sun.COM 
357934SMark.Phalan@Sun.COM #include <errno.h>
367934SMark.Phalan@Sun.COM #include <string.h>
377934SMark.Phalan@Sun.COM #include <stdio.h>
387934SMark.Phalan@Sun.COM #include <stdlib.h>
397934SMark.Phalan@Sun.COM #include <dlfcn.h>
407934SMark.Phalan@Sun.COM #include <unistd.h>
417934SMark.Phalan@Sun.COM #include <dirent.h>
427934SMark.Phalan@Sun.COM 
4312359SMark.Phalan@Sun.COM 
447934SMark.Phalan@Sun.COM /* Solaris Kerberos */
457934SMark.Phalan@Sun.COM #include <libintl.h>
46*12945Swill.fiveash@oracle.com #include <assert.h>
47*12945Swill.fiveash@oracle.com #include <security/pam_appl.h>
48*12945Swill.fiveash@oracle.com #include <ctype.h>
4912359SMark.Phalan@Sun.COM #include "k5-int.h"
5012943Swill.fiveash@oracle.com #include <ctype.h>
517934SMark.Phalan@Sun.COM 
527934SMark.Phalan@Sun.COM /*
537934SMark.Phalan@Sun.COM  * Q: What is this SILLYDECRYPT stuff about?
547934SMark.Phalan@Sun.COM  * A: When using the ActivCard Linux pkcs11 library (v2.0.1),
557934SMark.Phalan@Sun.COM  *    the decrypt function fails.  By inserting an extra
567934SMark.Phalan@Sun.COM  *    function call, which serves nothing but to change the
577934SMark.Phalan@Sun.COM  *    stack, we were able to work around the issue.  If the
587934SMark.Phalan@Sun.COM  *    ActivCard library is fixed in the future, this
597934SMark.Phalan@Sun.COM  *    definition and related code can be removed.
607934SMark.Phalan@Sun.COM  */
617934SMark.Phalan@Sun.COM #define SILLYDECRYPT
627934SMark.Phalan@Sun.COM 
637934SMark.Phalan@Sun.COM #include "pkinit_crypto_openssl.h"
647934SMark.Phalan@Sun.COM 
657934SMark.Phalan@Sun.COM /*
667934SMark.Phalan@Sun.COM  * Solaris Kerberos:
677934SMark.Phalan@Sun.COM  * Changed to a switch statement so gettext() can be used
687934SMark.Phalan@Sun.COM  * for internationization.
697934SMark.Phalan@Sun.COM  * Use defined constants rather than raw numbers for error codes.
707934SMark.Phalan@Sun.COM  */
717934SMark.Phalan@Sun.COM static char *
pkcs11_error_table(short code)727934SMark.Phalan@Sun.COM pkcs11_error_table(short code) {
737934SMark.Phalan@Sun.COM 	switch (code) {
747934SMark.Phalan@Sun.COM 	    case CKR_OK:
757934SMark.Phalan@Sun.COM 		return (gettext("ok"));
767934SMark.Phalan@Sun.COM 	    case CKR_CANCEL:
777934SMark.Phalan@Sun.COM 		return (gettext("cancel"));
787934SMark.Phalan@Sun.COM 	    case CKR_HOST_MEMORY:
797934SMark.Phalan@Sun.COM 		return (gettext("host memory"));
807934SMark.Phalan@Sun.COM 	    case CKR_SLOT_ID_INVALID:
817934SMark.Phalan@Sun.COM 		return (gettext("slot id invalid"));
827934SMark.Phalan@Sun.COM 	    case CKR_GENERAL_ERROR:
837934SMark.Phalan@Sun.COM 		return (gettext("general error"));
847934SMark.Phalan@Sun.COM 	    case CKR_FUNCTION_FAILED:
857934SMark.Phalan@Sun.COM 		return (gettext("function failed"));
867934SMark.Phalan@Sun.COM 	    case CKR_ARGUMENTS_BAD:
877934SMark.Phalan@Sun.COM 		return (gettext("arguments bad"));
887934SMark.Phalan@Sun.COM 	    case CKR_NO_EVENT:
897934SMark.Phalan@Sun.COM 		return (gettext("no event"));
907934SMark.Phalan@Sun.COM 	    case CKR_NEED_TO_CREATE_THREADS:
917934SMark.Phalan@Sun.COM 		return (gettext("need to create threads"));
927934SMark.Phalan@Sun.COM 	    case CKR_CANT_LOCK:
937934SMark.Phalan@Sun.COM 		return (gettext("cant lock"));
947934SMark.Phalan@Sun.COM 	    case CKR_ATTRIBUTE_READ_ONLY:
957934SMark.Phalan@Sun.COM 		return (gettext("attribute read only"));
967934SMark.Phalan@Sun.COM 	    case CKR_ATTRIBUTE_SENSITIVE:
977934SMark.Phalan@Sun.COM 		return (gettext("attribute sensitive"));
987934SMark.Phalan@Sun.COM 	    case CKR_ATTRIBUTE_TYPE_INVALID:
997934SMark.Phalan@Sun.COM 		return (gettext("attribute type invalid"));
1007934SMark.Phalan@Sun.COM 	    case CKR_ATTRIBUTE_VALUE_INVALID:
1017934SMark.Phalan@Sun.COM 		return (gettext("attribute value invalid"));
1027934SMark.Phalan@Sun.COM 	    case CKR_DATA_INVALID:
1037934SMark.Phalan@Sun.COM 		return (gettext("data invalid"));
1047934SMark.Phalan@Sun.COM 	    case CKR_DATA_LEN_RANGE:
1057934SMark.Phalan@Sun.COM 		return (gettext("data len range"));
1067934SMark.Phalan@Sun.COM 	    case CKR_DEVICE_ERROR:
1077934SMark.Phalan@Sun.COM 		return (gettext("device error"));
1087934SMark.Phalan@Sun.COM 	    case CKR_DEVICE_MEMORY:
1097934SMark.Phalan@Sun.COM 		return (gettext("device memory"));
1107934SMark.Phalan@Sun.COM 	    case CKR_DEVICE_REMOVED:
1117934SMark.Phalan@Sun.COM 		return (gettext("device removed"));
1127934SMark.Phalan@Sun.COM 	    case CKR_ENCRYPTED_DATA_INVALID:
1137934SMark.Phalan@Sun.COM 		return (gettext("encrypted data invalid"));
1147934SMark.Phalan@Sun.COM 	    case CKR_ENCRYPTED_DATA_LEN_RANGE:
1157934SMark.Phalan@Sun.COM 		return (gettext("encrypted data len range"));
1167934SMark.Phalan@Sun.COM 	    case CKR_FUNCTION_CANCELED:
1177934SMark.Phalan@Sun.COM 		return (gettext("function canceled"));
1187934SMark.Phalan@Sun.COM 	    case CKR_FUNCTION_NOT_PARALLEL:
1197934SMark.Phalan@Sun.COM 		return (gettext("function not parallel"));
1207934SMark.Phalan@Sun.COM 	    case CKR_FUNCTION_NOT_SUPPORTED:
1217934SMark.Phalan@Sun.COM 		return (gettext("function not supported"));
1227934SMark.Phalan@Sun.COM 	    case CKR_KEY_HANDLE_INVALID:
1237934SMark.Phalan@Sun.COM 		return (gettext("key handle invalid"));
1247934SMark.Phalan@Sun.COM 	    case CKR_KEY_SIZE_RANGE:
1257934SMark.Phalan@Sun.COM 		return (gettext("key size range"));
1267934SMark.Phalan@Sun.COM 	    case CKR_KEY_TYPE_INCONSISTENT:
1277934SMark.Phalan@Sun.COM 		return (gettext("key type inconsistent"));
1287934SMark.Phalan@Sun.COM 	    case CKR_KEY_NOT_NEEDED:
1297934SMark.Phalan@Sun.COM 		return (gettext("key not needed"));
1307934SMark.Phalan@Sun.COM 	    case CKR_KEY_CHANGED:
1317934SMark.Phalan@Sun.COM 		return (gettext("key changed"));
1327934SMark.Phalan@Sun.COM 	    case CKR_KEY_NEEDED:
1337934SMark.Phalan@Sun.COM 		return (gettext("key needed"));
1347934SMark.Phalan@Sun.COM 	    case CKR_KEY_INDIGESTIBLE:
1357934SMark.Phalan@Sun.COM 		return (gettext("key indigestible"));
1367934SMark.Phalan@Sun.COM 	    case CKR_KEY_FUNCTION_NOT_PERMITTED:
1377934SMark.Phalan@Sun.COM 		return (gettext("key function not permitted"));
1387934SMark.Phalan@Sun.COM 	    case CKR_KEY_NOT_WRAPPABLE:
1397934SMark.Phalan@Sun.COM 		return (gettext("key not wrappable"));
1407934SMark.Phalan@Sun.COM 	    case CKR_KEY_UNEXTRACTABLE:
1417934SMark.Phalan@Sun.COM 		return (gettext("key unextractable"));
1427934SMark.Phalan@Sun.COM 	    case CKR_MECHANISM_INVALID:
1437934SMark.Phalan@Sun.COM 		return (gettext("mechanism invalid"));
1447934SMark.Phalan@Sun.COM 	    case CKR_MECHANISM_PARAM_INVALID:
1457934SMark.Phalan@Sun.COM 		return (gettext("mechanism param invalid"));
1467934SMark.Phalan@Sun.COM 	    case CKR_OBJECT_HANDLE_INVALID:
1477934SMark.Phalan@Sun.COM 		return (gettext("object handle invalid"));
1487934SMark.Phalan@Sun.COM 	    case CKR_OPERATION_ACTIVE:
1497934SMark.Phalan@Sun.COM 		return (gettext("operation active"));
1507934SMark.Phalan@Sun.COM 	    case CKR_OPERATION_NOT_INITIALIZED:
1517934SMark.Phalan@Sun.COM 		return (gettext("operation not initialized"));
1527934SMark.Phalan@Sun.COM 	    case CKR_PIN_INCORRECT:
1537934SMark.Phalan@Sun.COM 		return (gettext("pin incorrect"));
1547934SMark.Phalan@Sun.COM 	    case CKR_PIN_INVALID:
1557934SMark.Phalan@Sun.COM 		return (gettext("pin invalid"));
1567934SMark.Phalan@Sun.COM 	    case CKR_PIN_LEN_RANGE:
1577934SMark.Phalan@Sun.COM 		return (gettext("pin len range"));
1587934SMark.Phalan@Sun.COM 	    case CKR_PIN_EXPIRED:
1597934SMark.Phalan@Sun.COM 		return (gettext("pin expired"));
1607934SMark.Phalan@Sun.COM 	    case CKR_PIN_LOCKED:
1617934SMark.Phalan@Sun.COM 		return (gettext("pin locked"));
1627934SMark.Phalan@Sun.COM 	    case CKR_SESSION_CLOSED:
1637934SMark.Phalan@Sun.COM 		return (gettext("session closed"));
1647934SMark.Phalan@Sun.COM 	    case CKR_SESSION_COUNT:
1657934SMark.Phalan@Sun.COM 		return (gettext("session count"));
1667934SMark.Phalan@Sun.COM 	    case CKR_SESSION_HANDLE_INVALID:
1677934SMark.Phalan@Sun.COM 		return (gettext("session handle invalid"));
1687934SMark.Phalan@Sun.COM 	    case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
1697934SMark.Phalan@Sun.COM 		return (gettext("session parallel not supported"));
1707934SMark.Phalan@Sun.COM 	    case CKR_SESSION_READ_ONLY:
1717934SMark.Phalan@Sun.COM 		return (gettext("session read only"));
1727934SMark.Phalan@Sun.COM 	    case CKR_SESSION_EXISTS:
1737934SMark.Phalan@Sun.COM 		return (gettext("session exists"));
1747934SMark.Phalan@Sun.COM 	    case CKR_SESSION_READ_ONLY_EXISTS:
1757934SMark.Phalan@Sun.COM 		return (gettext("session read only exists"));
1767934SMark.Phalan@Sun.COM 	    case CKR_SESSION_READ_WRITE_SO_EXISTS:
1777934SMark.Phalan@Sun.COM 		return (gettext("session read write so exists"));
1787934SMark.Phalan@Sun.COM 	    case CKR_SIGNATURE_INVALID:
1797934SMark.Phalan@Sun.COM 		return (gettext("signature invalid"));
1807934SMark.Phalan@Sun.COM 	    case CKR_SIGNATURE_LEN_RANGE:
1817934SMark.Phalan@Sun.COM 		return (gettext("signature len range"));
1827934SMark.Phalan@Sun.COM 	    case CKR_TEMPLATE_INCOMPLETE:
1837934SMark.Phalan@Sun.COM 		return (gettext("template incomplete"));
1847934SMark.Phalan@Sun.COM 	    case CKR_TEMPLATE_INCONSISTENT:
1857934SMark.Phalan@Sun.COM 		return (gettext("template inconsistent"));
1867934SMark.Phalan@Sun.COM 	    case CKR_TOKEN_NOT_PRESENT:
1877934SMark.Phalan@Sun.COM 		return (gettext("token not present"));
1887934SMark.Phalan@Sun.COM 	    case CKR_TOKEN_NOT_RECOGNIZED:
1897934SMark.Phalan@Sun.COM 		return (gettext("token not recognized"));
1907934SMark.Phalan@Sun.COM 	    case CKR_TOKEN_WRITE_PROTECTED:
1917934SMark.Phalan@Sun.COM 		return (gettext("token write protected"));
1927934SMark.Phalan@Sun.COM 	    case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
1937934SMark.Phalan@Sun.COM 		return (gettext("unwrapping key handle invalid"));
1947934SMark.Phalan@Sun.COM 	    case CKR_UNWRAPPING_KEY_SIZE_RANGE:
1957934SMark.Phalan@Sun.COM 		return (gettext("unwrapping key size range"));
1967934SMark.Phalan@Sun.COM 	    case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
1977934SMark.Phalan@Sun.COM 		return (gettext("unwrapping key type inconsistent"));
1987934SMark.Phalan@Sun.COM 	    case CKR_USER_ALREADY_LOGGED_IN:
1997934SMark.Phalan@Sun.COM 		return (gettext("user already logged in"));
2007934SMark.Phalan@Sun.COM 	    case CKR_USER_NOT_LOGGED_IN:
2017934SMark.Phalan@Sun.COM 		return (gettext("user not logged in"));
2027934SMark.Phalan@Sun.COM 	    case CKR_USER_PIN_NOT_INITIALIZED:
2037934SMark.Phalan@Sun.COM 		return (gettext("user pin not initialized"));
2047934SMark.Phalan@Sun.COM 	    case CKR_USER_TYPE_INVALID:
2057934SMark.Phalan@Sun.COM 		return (gettext("user type invalid"));
2067934SMark.Phalan@Sun.COM 	    case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
2077934SMark.Phalan@Sun.COM 		return (gettext("user another already logged in"));
2087934SMark.Phalan@Sun.COM 	    case CKR_USER_TOO_MANY_TYPES:
2097934SMark.Phalan@Sun.COM 		return (gettext("user too many types"));
2107934SMark.Phalan@Sun.COM 	    case CKR_WRAPPED_KEY_INVALID:
2117934SMark.Phalan@Sun.COM 		return (gettext("wrapped key invalid"));
2127934SMark.Phalan@Sun.COM 	    case CKR_WRAPPED_KEY_LEN_RANGE:
2137934SMark.Phalan@Sun.COM 		return (gettext("wrapped key len range"));
2147934SMark.Phalan@Sun.COM 	    case CKR_WRAPPING_KEY_HANDLE_INVALID:
2157934SMark.Phalan@Sun.COM 		return (gettext("wrapping key handle invalid"));
2167934SMark.Phalan@Sun.COM 	    case CKR_WRAPPING_KEY_SIZE_RANGE:
2177934SMark.Phalan@Sun.COM 		return (gettext("wrapping key size range"));
2187934SMark.Phalan@Sun.COM 	    case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
2197934SMark.Phalan@Sun.COM 		return (gettext("wrapping key type inconsistent"));
2207934SMark.Phalan@Sun.COM 	    case CKR_RANDOM_SEED_NOT_SUPPORTED:
2217934SMark.Phalan@Sun.COM 		return (gettext("random seed not supported"));
2227934SMark.Phalan@Sun.COM 	    case CKR_RANDOM_NO_RNG:
2237934SMark.Phalan@Sun.COM 		return (gettext("random no rng"));
2247934SMark.Phalan@Sun.COM 	    case CKR_DOMAIN_PARAMS_INVALID:
2257934SMark.Phalan@Sun.COM 		return (gettext("domain params invalid"));
2267934SMark.Phalan@Sun.COM 	    case CKR_BUFFER_TOO_SMALL:
2277934SMark.Phalan@Sun.COM 		return (gettext("buffer too small"));
2287934SMark.Phalan@Sun.COM 	    case CKR_SAVED_STATE_INVALID:
2297934SMark.Phalan@Sun.COM 		return (gettext("saved state invalid"));
2307934SMark.Phalan@Sun.COM 	    case CKR_INFORMATION_SENSITIVE:
2317934SMark.Phalan@Sun.COM 		return (gettext("information sensitive"));
2327934SMark.Phalan@Sun.COM 	    case CKR_STATE_UNSAVEABLE:
2337934SMark.Phalan@Sun.COM 		return (gettext("state unsaveable"));
2347934SMark.Phalan@Sun.COM 	    case CKR_CRYPTOKI_NOT_INITIALIZED:
2357934SMark.Phalan@Sun.COM 		return (gettext("cryptoki not initialized"));
2367934SMark.Phalan@Sun.COM 	    case CKR_CRYPTOKI_ALREADY_INITIALIZED:
2377934SMark.Phalan@Sun.COM 		return (gettext("cryptoki already initialized"));
2387934SMark.Phalan@Sun.COM 	    case CKR_MUTEX_BAD:
2397934SMark.Phalan@Sun.COM 		return (gettext("mutex bad"));
2407934SMark.Phalan@Sun.COM 	    case CKR_MUTEX_NOT_LOCKED:
2417934SMark.Phalan@Sun.COM 		return (gettext("mutex not locked"));
2427934SMark.Phalan@Sun.COM 	    case CKR_FUNCTION_REJECTED:
2437934SMark.Phalan@Sun.COM 		return (gettext("function rejected"));
2447934SMark.Phalan@Sun.COM 	    default:
2457934SMark.Phalan@Sun.COM 		return (gettext("unknown error"));
2467934SMark.Phalan@Sun.COM 	}
2477934SMark.Phalan@Sun.COM }
2487934SMark.Phalan@Sun.COM 
2497934SMark.Phalan@Sun.COM /* DH parameters */
2507934SMark.Phalan@Sun.COM unsigned char pkinit_1024_dhprime[128] = {
2517934SMark.Phalan@Sun.COM     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2527934SMark.Phalan@Sun.COM     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
2537934SMark.Phalan@Sun.COM     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
2547934SMark.Phalan@Sun.COM     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
2557934SMark.Phalan@Sun.COM     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
2567934SMark.Phalan@Sun.COM     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
2577934SMark.Phalan@Sun.COM     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
2587934SMark.Phalan@Sun.COM     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
2597934SMark.Phalan@Sun.COM     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
2607934SMark.Phalan@Sun.COM     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
2617934SMark.Phalan@Sun.COM     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
2627934SMark.Phalan@Sun.COM     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
2637934SMark.Phalan@Sun.COM     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
2647934SMark.Phalan@Sun.COM     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
2657934SMark.Phalan@Sun.COM     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
2667934SMark.Phalan@Sun.COM     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
2677934SMark.Phalan@Sun.COM };
2687934SMark.Phalan@Sun.COM 
2697934SMark.Phalan@Sun.COM unsigned char pkinit_2048_dhprime[2048/8] = {
2707934SMark.Phalan@Sun.COM     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2717934SMark.Phalan@Sun.COM     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
2727934SMark.Phalan@Sun.COM     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
2737934SMark.Phalan@Sun.COM     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
2747934SMark.Phalan@Sun.COM     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
2757934SMark.Phalan@Sun.COM     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
2767934SMark.Phalan@Sun.COM     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
2777934SMark.Phalan@Sun.COM     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
2787934SMark.Phalan@Sun.COM     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
2797934SMark.Phalan@Sun.COM     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
2807934SMark.Phalan@Sun.COM     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
2817934SMark.Phalan@Sun.COM     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
2827934SMark.Phalan@Sun.COM     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
2837934SMark.Phalan@Sun.COM     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
2847934SMark.Phalan@Sun.COM     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
2857934SMark.Phalan@Sun.COM     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
2867934SMark.Phalan@Sun.COM     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
2877934SMark.Phalan@Sun.COM     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
2887934SMark.Phalan@Sun.COM     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
2897934SMark.Phalan@Sun.COM     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
2907934SMark.Phalan@Sun.COM     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
2917934SMark.Phalan@Sun.COM     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
2927934SMark.Phalan@Sun.COM     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
2937934SMark.Phalan@Sun.COM     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
2947934SMark.Phalan@Sun.COM     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
2957934SMark.Phalan@Sun.COM     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
2967934SMark.Phalan@Sun.COM     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
2977934SMark.Phalan@Sun.COM     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
2987934SMark.Phalan@Sun.COM     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
2997934SMark.Phalan@Sun.COM     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
3007934SMark.Phalan@Sun.COM     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
3017934SMark.Phalan@Sun.COM     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
3027934SMark.Phalan@Sun.COM };
3037934SMark.Phalan@Sun.COM 
3047934SMark.Phalan@Sun.COM unsigned char pkinit_4096_dhprime[4096/8] = {
3057934SMark.Phalan@Sun.COM     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
3067934SMark.Phalan@Sun.COM     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
3077934SMark.Phalan@Sun.COM     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
3087934SMark.Phalan@Sun.COM     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
3097934SMark.Phalan@Sun.COM     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
3107934SMark.Phalan@Sun.COM     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
3117934SMark.Phalan@Sun.COM     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
3127934SMark.Phalan@Sun.COM     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
3137934SMark.Phalan@Sun.COM     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
3147934SMark.Phalan@Sun.COM     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
3157934SMark.Phalan@Sun.COM     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
3167934SMark.Phalan@Sun.COM     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
3177934SMark.Phalan@Sun.COM     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
3187934SMark.Phalan@Sun.COM     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
3197934SMark.Phalan@Sun.COM     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
3207934SMark.Phalan@Sun.COM     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
3217934SMark.Phalan@Sun.COM     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
3227934SMark.Phalan@Sun.COM     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
3237934SMark.Phalan@Sun.COM     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
3247934SMark.Phalan@Sun.COM     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
3257934SMark.Phalan@Sun.COM     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
3267934SMark.Phalan@Sun.COM     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
3277934SMark.Phalan@Sun.COM     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
3287934SMark.Phalan@Sun.COM     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
3297934SMark.Phalan@Sun.COM     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
3307934SMark.Phalan@Sun.COM     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
3317934SMark.Phalan@Sun.COM     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
3327934SMark.Phalan@Sun.COM     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
3337934SMark.Phalan@Sun.COM     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
3347934SMark.Phalan@Sun.COM     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
3357934SMark.Phalan@Sun.COM     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
3367934SMark.Phalan@Sun.COM     0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
3377934SMark.Phalan@Sun.COM     0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
3387934SMark.Phalan@Sun.COM     0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
3397934SMark.Phalan@Sun.COM     0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
3407934SMark.Phalan@Sun.COM     0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
3417934SMark.Phalan@Sun.COM     0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
3427934SMark.Phalan@Sun.COM     0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
3437934SMark.Phalan@Sun.COM     0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
3447934SMark.Phalan@Sun.COM     0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
3457934SMark.Phalan@Sun.COM     0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
3467934SMark.Phalan@Sun.COM     0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
3477934SMark.Phalan@Sun.COM     0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
3487934SMark.Phalan@Sun.COM     0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
3497934SMark.Phalan@Sun.COM     0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
3507934SMark.Phalan@Sun.COM     0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
3517934SMark.Phalan@Sun.COM     0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
3527934SMark.Phalan@Sun.COM     0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
3537934SMark.Phalan@Sun.COM     0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
3547934SMark.Phalan@Sun.COM     0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
3557934SMark.Phalan@Sun.COM     0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
3567934SMark.Phalan@Sun.COM     0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
3577934SMark.Phalan@Sun.COM     0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
3587934SMark.Phalan@Sun.COM     0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
3597934SMark.Phalan@Sun.COM     0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
3607934SMark.Phalan@Sun.COM     0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
3617934SMark.Phalan@Sun.COM     0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
3627934SMark.Phalan@Sun.COM     0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
3637934SMark.Phalan@Sun.COM     0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
3647934SMark.Phalan@Sun.COM     0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
3657934SMark.Phalan@Sun.COM     0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
3667934SMark.Phalan@Sun.COM     0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
3677934SMark.Phalan@Sun.COM     0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
3687934SMark.Phalan@Sun.COM     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
3697934SMark.Phalan@Sun.COM };
3707934SMark.Phalan@Sun.COM 
37112359SMark.Phalan@Sun.COM /* Solaris Kerberos */
37212359SMark.Phalan@Sun.COM static k5_mutex_t oids_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
3737934SMark.Phalan@Sun.COM static int pkinit_oids_refs = 0;
3747934SMark.Phalan@Sun.COM 
3757934SMark.Phalan@Sun.COM krb5_error_code
pkinit_init_plg_crypto(pkinit_plg_crypto_context * cryptoctx)3767934SMark.Phalan@Sun.COM pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) {
3777934SMark.Phalan@Sun.COM 
3787934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
3797934SMark.Phalan@Sun.COM     pkinit_plg_crypto_context ctx = NULL;
3807934SMark.Phalan@Sun.COM 
3817934SMark.Phalan@Sun.COM     /* initialize openssl routines */
38212359SMark.Phalan@Sun.COM     /* Solaris Kerberos */
38312359SMark.Phalan@Sun.COM     retval = openssl_init();
38412359SMark.Phalan@Sun.COM     if (retval != 0)
38512359SMark.Phalan@Sun.COM 	goto out;
3867934SMark.Phalan@Sun.COM 
3877934SMark.Phalan@Sun.COM     ctx = (pkinit_plg_crypto_context)malloc(sizeof(*ctx));
3887934SMark.Phalan@Sun.COM     if (ctx == NULL)
3897934SMark.Phalan@Sun.COM 	goto out;
3907934SMark.Phalan@Sun.COM     (void) memset(ctx, 0, sizeof(*ctx));
3917934SMark.Phalan@Sun.COM 
3927934SMark.Phalan@Sun.COM     pkiDebug("%s: initializing openssl crypto context at %p\n",
3937934SMark.Phalan@Sun.COM 	     __FUNCTION__, ctx);
3947934SMark.Phalan@Sun.COM     retval = pkinit_init_pkinit_oids(ctx);
3957934SMark.Phalan@Sun.COM     if (retval)
3967934SMark.Phalan@Sun.COM 	goto out;
3977934SMark.Phalan@Sun.COM 
3987934SMark.Phalan@Sun.COM     retval = pkinit_init_dh_params(ctx);
3997934SMark.Phalan@Sun.COM     if (retval)
4007934SMark.Phalan@Sun.COM 	goto out;
4017934SMark.Phalan@Sun.COM 
4027934SMark.Phalan@Sun.COM     *cryptoctx = ctx;
4037934SMark.Phalan@Sun.COM 
4047934SMark.Phalan@Sun.COM out:
4057934SMark.Phalan@Sun.COM     if (retval && ctx != NULL)
4067934SMark.Phalan@Sun.COM 	    pkinit_fini_plg_crypto(ctx);
4077934SMark.Phalan@Sun.COM 
4087934SMark.Phalan@Sun.COM     return retval;
4097934SMark.Phalan@Sun.COM }
4107934SMark.Phalan@Sun.COM 
4117934SMark.Phalan@Sun.COM void
pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)4127934SMark.Phalan@Sun.COM pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)
4137934SMark.Phalan@Sun.COM {
4147934SMark.Phalan@Sun.COM     pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx);
4157934SMark.Phalan@Sun.COM 
4167934SMark.Phalan@Sun.COM     if (cryptoctx == NULL)
4177934SMark.Phalan@Sun.COM 	return;
4187934SMark.Phalan@Sun.COM     pkinit_fini_pkinit_oids(cryptoctx);
4197934SMark.Phalan@Sun.COM     pkinit_fini_dh_params(cryptoctx);
4207934SMark.Phalan@Sun.COM     free(cryptoctx);
4217934SMark.Phalan@Sun.COM }
4227934SMark.Phalan@Sun.COM 
4237934SMark.Phalan@Sun.COM krb5_error_code
pkinit_init_identity_crypto(pkinit_identity_crypto_context * idctx)4247934SMark.Phalan@Sun.COM pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
4257934SMark.Phalan@Sun.COM {
4267934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
4277934SMark.Phalan@Sun.COM     pkinit_identity_crypto_context ctx = NULL;
4287934SMark.Phalan@Sun.COM 
4297934SMark.Phalan@Sun.COM     ctx = (pkinit_identity_crypto_context)malloc(sizeof(*ctx));
4307934SMark.Phalan@Sun.COM     if (ctx == NULL)
4317934SMark.Phalan@Sun.COM 	goto out;
4327934SMark.Phalan@Sun.COM     (void) memset(ctx, 0, sizeof(*ctx));
4337934SMark.Phalan@Sun.COM 
4347934SMark.Phalan@Sun.COM     retval = pkinit_init_certs(ctx);
4357934SMark.Phalan@Sun.COM     if (retval)
4367934SMark.Phalan@Sun.COM 	goto out;
4377934SMark.Phalan@Sun.COM 
4387934SMark.Phalan@Sun.COM     retval = pkinit_init_pkcs11(ctx);
4397934SMark.Phalan@Sun.COM     if (retval)
4407934SMark.Phalan@Sun.COM 	goto out;
4417934SMark.Phalan@Sun.COM 
4427934SMark.Phalan@Sun.COM     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
4437934SMark.Phalan@Sun.COM     *idctx = ctx;
4447934SMark.Phalan@Sun.COM 
4457934SMark.Phalan@Sun.COM out:
4467934SMark.Phalan@Sun.COM     if (retval) {
4477934SMark.Phalan@Sun.COM 	if (ctx)
4487934SMark.Phalan@Sun.COM 	    pkinit_fini_identity_crypto(ctx);
4497934SMark.Phalan@Sun.COM     }
4507934SMark.Phalan@Sun.COM 
4517934SMark.Phalan@Sun.COM     return retval;
4527934SMark.Phalan@Sun.COM }
4537934SMark.Phalan@Sun.COM 
4547934SMark.Phalan@Sun.COM void
pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)4557934SMark.Phalan@Sun.COM pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
4567934SMark.Phalan@Sun.COM {
4577934SMark.Phalan@Sun.COM     if (idctx == NULL)
4587934SMark.Phalan@Sun.COM 	return;
4597934SMark.Phalan@Sun.COM 
4607934SMark.Phalan@Sun.COM     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, idctx);
4617934SMark.Phalan@Sun.COM     pkinit_fini_certs(idctx);
4627934SMark.Phalan@Sun.COM     pkinit_fini_pkcs11(idctx);
4637934SMark.Phalan@Sun.COM     free(idctx);
4647934SMark.Phalan@Sun.COM }
4657934SMark.Phalan@Sun.COM 
4667934SMark.Phalan@Sun.COM krb5_error_code
pkinit_init_req_crypto(pkinit_req_crypto_context * cryptoctx)4677934SMark.Phalan@Sun.COM pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
4687934SMark.Phalan@Sun.COM {
4697934SMark.Phalan@Sun.COM 
4707934SMark.Phalan@Sun.COM     pkinit_req_crypto_context ctx = NULL;
4717934SMark.Phalan@Sun.COM 
4727934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
4737934SMark.Phalan@Sun.COM     if (cryptoctx == NULL)
4747934SMark.Phalan@Sun.COM 	return EINVAL;
4757934SMark.Phalan@Sun.COM 
4767934SMark.Phalan@Sun.COM     ctx = (pkinit_req_crypto_context)malloc(sizeof(*ctx));
4777934SMark.Phalan@Sun.COM     if (ctx == NULL)
4787934SMark.Phalan@Sun.COM 	return ENOMEM;
4797934SMark.Phalan@Sun.COM     (void) memset(ctx, 0, sizeof(*ctx));
4807934SMark.Phalan@Sun.COM 
4817934SMark.Phalan@Sun.COM     ctx->dh = NULL;
4827934SMark.Phalan@Sun.COM     ctx->received_cert = NULL;
4837934SMark.Phalan@Sun.COM 
4847934SMark.Phalan@Sun.COM     *cryptoctx = ctx;
4857934SMark.Phalan@Sun.COM 
4867934SMark.Phalan@Sun.COM     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
4877934SMark.Phalan@Sun.COM 
4887934SMark.Phalan@Sun.COM     return 0;
4897934SMark.Phalan@Sun.COM }
4907934SMark.Phalan@Sun.COM 
4917934SMark.Phalan@Sun.COM void
pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)4927934SMark.Phalan@Sun.COM pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
4937934SMark.Phalan@Sun.COM {
4947934SMark.Phalan@Sun.COM     if (req_cryptoctx == NULL)
4957934SMark.Phalan@Sun.COM 	return;
4967934SMark.Phalan@Sun.COM 
4977934SMark.Phalan@Sun.COM     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, req_cryptoctx);
4987934SMark.Phalan@Sun.COM     if (req_cryptoctx->dh != NULL)
4997934SMark.Phalan@Sun.COM       DH_free(req_cryptoctx->dh);
5007934SMark.Phalan@Sun.COM     if (req_cryptoctx->received_cert != NULL)
5017934SMark.Phalan@Sun.COM       X509_free(req_cryptoctx->received_cert);
5027934SMark.Phalan@Sun.COM 
5037934SMark.Phalan@Sun.COM     free(req_cryptoctx);
5047934SMark.Phalan@Sun.COM }
5057934SMark.Phalan@Sun.COM 
5067934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)5077934SMark.Phalan@Sun.COM pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
5087934SMark.Phalan@Sun.COM {
5097934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
5107934SMark.Phalan@Sun.COM     int nid = 0;
5117934SMark.Phalan@Sun.COM 
5127934SMark.Phalan@Sun.COM     /*
5137934SMark.Phalan@Sun.COM      * If OpenSSL already knows about the OID, use the
5147934SMark.Phalan@Sun.COM      * existing definition. Otherwise, create an OID object.
5157934SMark.Phalan@Sun.COM      */
5167934SMark.Phalan@Sun.COM     #define CREATE_OBJ_IF_NEEDED(oid, vn, sn, ln) \
5177934SMark.Phalan@Sun.COM 	nid = OBJ_txt2nid(oid); \
5187934SMark.Phalan@Sun.COM 	if (nid == NID_undef) { \
5197934SMark.Phalan@Sun.COM 	    nid = OBJ_create(oid, sn, ln); \
5207934SMark.Phalan@Sun.COM 	    if (nid == NID_undef) { \
5217934SMark.Phalan@Sun.COM 		pkiDebug("Error creating oid object for '%s'\n", oid); \
5227934SMark.Phalan@Sun.COM 		goto out; \
5237934SMark.Phalan@Sun.COM 	    } \
5247934SMark.Phalan@Sun.COM 	} \
5257934SMark.Phalan@Sun.COM 	ctx->vn = OBJ_nid2obj(nid);
5267934SMark.Phalan@Sun.COM 
52712359SMark.Phalan@Sun.COM     /* Solaris Kerberos */
52812359SMark.Phalan@Sun.COM     retval = k5_mutex_lock(&oids_mutex);
52912359SMark.Phalan@Sun.COM     if (retval != 0)
53012359SMark.Phalan@Sun.COM 	goto out;
53112359SMark.Phalan@Sun.COM 
5327934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.2", id_pkinit_san,
5337934SMark.Phalan@Sun.COM 			 "id-pkinit-san", "KRB5PrincipalName");
5347934SMark.Phalan@Sun.COM 
5357934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.1", id_pkinit_authData,
5367934SMark.Phalan@Sun.COM 			 "id-pkinit-authdata", "PKINIT signedAuthPack");
5377934SMark.Phalan@Sun.COM 
5387934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.2", id_pkinit_DHKeyData,
5397934SMark.Phalan@Sun.COM 			 "id-pkinit-DHKeyData", "PKINIT dhSignedData");
5407934SMark.Phalan@Sun.COM 
5417934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.3", id_pkinit_rkeyData,
5427934SMark.Phalan@Sun.COM 			 "id-pkinit-rkeyData", "PKINIT encKeyPack");
5437934SMark.Phalan@Sun.COM 
5447934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.4", id_pkinit_KPClientAuth,
5457934SMark.Phalan@Sun.COM 			 "id-pkinit-KPClientAuth", "PKINIT Client EKU");
5467934SMark.Phalan@Sun.COM 
5477934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.5", id_pkinit_KPKdc,
5487934SMark.Phalan@Sun.COM 			 "id-pkinit-KPKdc", "KDC EKU");
5497934SMark.Phalan@Sun.COM 
5507934SMark.Phalan@Sun.COM #if 0
5517934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.2.840.113549.1.7.1", id_pkinit_authData9,
5527934SMark.Phalan@Sun.COM 			 "id-pkcs7-data", "PKCS7 data");
5537934SMark.Phalan@Sun.COM #else
5547934SMark.Phalan@Sun.COM     /* See note in pkinit_pkcs7type2oid() */
5557934SMark.Phalan@Sun.COM     ctx->id_pkinit_authData9 = NULL;
5567934SMark.Phalan@Sun.COM #endif
5577934SMark.Phalan@Sun.COM 
5587934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.2", id_ms_kp_sc_logon,
5597934SMark.Phalan@Sun.COM 			 "id-ms-kp-sc-logon EKU", "Microsoft SmartCard Login EKU");
5607934SMark.Phalan@Sun.COM 
5617934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.3", id_ms_san_upn,
5627934SMark.Phalan@Sun.COM 			 "id-ms-san-upn", "Microsoft Universal Principal Name");
5637934SMark.Phalan@Sun.COM 
5647934SMark.Phalan@Sun.COM     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.5.7.3.1", id_kp_serverAuth,
5657934SMark.Phalan@Sun.COM 			 "id-kp-serverAuth EKU", "Server Authentication EKU");
5667934SMark.Phalan@Sun.COM 
5677934SMark.Phalan@Sun.COM     /* Success */
5687934SMark.Phalan@Sun.COM     retval = 0;
5697934SMark.Phalan@Sun.COM 
5707934SMark.Phalan@Sun.COM     pkinit_oids_refs++;
57112359SMark.Phalan@Sun.COM     /* Solaris Kerberos */
57212359SMark.Phalan@Sun.COM     k5_mutex_unlock(&oids_mutex);
5737934SMark.Phalan@Sun.COM 
5747934SMark.Phalan@Sun.COM out:
5757934SMark.Phalan@Sun.COM     return retval;
5767934SMark.Phalan@Sun.COM }
5777934SMark.Phalan@Sun.COM 
5787934SMark.Phalan@Sun.COM static krb5_error_code
get_cert(char * filename,X509 ** retcert)5797934SMark.Phalan@Sun.COM get_cert(char *filename, X509 **retcert)
5807934SMark.Phalan@Sun.COM {
5817934SMark.Phalan@Sun.COM     X509 *cert = NULL;
5827934SMark.Phalan@Sun.COM     BIO *tmp = NULL;
5837934SMark.Phalan@Sun.COM     int code;
5847934SMark.Phalan@Sun.COM     krb5_error_code retval;
5857934SMark.Phalan@Sun.COM 
5867934SMark.Phalan@Sun.COM     if (filename == NULL || retcert == NULL)
5877934SMark.Phalan@Sun.COM 	return EINVAL;
5887934SMark.Phalan@Sun.COM 
5897934SMark.Phalan@Sun.COM     *retcert = NULL;
5907934SMark.Phalan@Sun.COM 
5917934SMark.Phalan@Sun.COM     tmp = BIO_new(BIO_s_file());
5927934SMark.Phalan@Sun.COM     if (tmp == NULL)
5937934SMark.Phalan@Sun.COM 	return ENOMEM;
5947934SMark.Phalan@Sun.COM 
5957934SMark.Phalan@Sun.COM     code = BIO_read_filename(tmp, filename);
5967934SMark.Phalan@Sun.COM     if (code == 0) {
5977934SMark.Phalan@Sun.COM 	retval = errno;
5987934SMark.Phalan@Sun.COM 	goto cleanup;
5997934SMark.Phalan@Sun.COM     }
6007934SMark.Phalan@Sun.COM 
6017934SMark.Phalan@Sun.COM     cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL);
6027934SMark.Phalan@Sun.COM     if (cert == NULL) {
6037934SMark.Phalan@Sun.COM 	retval = EIO;
6047934SMark.Phalan@Sun.COM 	pkiDebug("failed to read certificate from %s\n", filename);
6057934SMark.Phalan@Sun.COM 	goto cleanup;
6067934SMark.Phalan@Sun.COM     }
6077934SMark.Phalan@Sun.COM     *retcert = cert;
6087934SMark.Phalan@Sun.COM     retval = 0;
6097934SMark.Phalan@Sun.COM cleanup:
6107934SMark.Phalan@Sun.COM     if (tmp != NULL)
6117934SMark.Phalan@Sun.COM 	BIO_free(tmp);
6127934SMark.Phalan@Sun.COM     return retval;
6137934SMark.Phalan@Sun.COM }
6147934SMark.Phalan@Sun.COM 
6157934SMark.Phalan@Sun.COM static krb5_error_code
get_key(char * filename,EVP_PKEY ** retkey)6167934SMark.Phalan@Sun.COM get_key(char *filename, EVP_PKEY **retkey)
6177934SMark.Phalan@Sun.COM {
6187934SMark.Phalan@Sun.COM     EVP_PKEY *pkey = NULL;
6197934SMark.Phalan@Sun.COM     BIO *tmp = NULL;
6207934SMark.Phalan@Sun.COM     int code;
6217934SMark.Phalan@Sun.COM     krb5_error_code retval;
6227934SMark.Phalan@Sun.COM 
6237934SMark.Phalan@Sun.COM     if (filename == NULL || retkey == NULL)
6247934SMark.Phalan@Sun.COM 	return EINVAL;
6257934SMark.Phalan@Sun.COM 
6267934SMark.Phalan@Sun.COM     tmp = BIO_new(BIO_s_file());
6277934SMark.Phalan@Sun.COM     if (tmp == NULL)
6287934SMark.Phalan@Sun.COM 	return ENOMEM;
6297934SMark.Phalan@Sun.COM 
6307934SMark.Phalan@Sun.COM     code = BIO_read_filename(tmp, filename);
6317934SMark.Phalan@Sun.COM     if (code == 0) {
6327934SMark.Phalan@Sun.COM 	retval = errno;
6337934SMark.Phalan@Sun.COM 	goto cleanup;
6347934SMark.Phalan@Sun.COM     }
6357934SMark.Phalan@Sun.COM     pkey = (EVP_PKEY *) PEM_read_bio_PrivateKey(tmp, NULL, NULL, NULL);
6367934SMark.Phalan@Sun.COM     if (pkey == NULL) {
6377934SMark.Phalan@Sun.COM 	retval = EIO;
6387934SMark.Phalan@Sun.COM 	pkiDebug("failed to read private key from %s\n", filename);
6397934SMark.Phalan@Sun.COM 	goto cleanup;
6407934SMark.Phalan@Sun.COM     }
6417934SMark.Phalan@Sun.COM     *retkey = pkey;
6427934SMark.Phalan@Sun.COM     retval = 0;
6437934SMark.Phalan@Sun.COM cleanup:
6447934SMark.Phalan@Sun.COM     if (tmp != NULL)
6457934SMark.Phalan@Sun.COM 	BIO_free(tmp);
6467934SMark.Phalan@Sun.COM     return retval;
6477934SMark.Phalan@Sun.COM }
6487934SMark.Phalan@Sun.COM 
6497934SMark.Phalan@Sun.COM static void
pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)6507934SMark.Phalan@Sun.COM pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
6517934SMark.Phalan@Sun.COM {
6527934SMark.Phalan@Sun.COM     if (ctx == NULL)
6537934SMark.Phalan@Sun.COM 	return;
6547934SMark.Phalan@Sun.COM 
6557934SMark.Phalan@Sun.COM     /* Only call OBJ_cleanup once! */
65612359SMark.Phalan@Sun.COM     /* Solaris Kerberos: locking */
65712359SMark.Phalan@Sun.COM     k5_mutex_lock(&oids_mutex);
65812359SMark.Phalan@Sun.COM     if (--pkinit_oids_refs == 0)
6597934SMark.Phalan@Sun.COM 	OBJ_cleanup();
66012359SMark.Phalan@Sun.COM     k5_mutex_unlock(&oids_mutex);
6617934SMark.Phalan@Sun.COM }
6627934SMark.Phalan@Sun.COM 
6637934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)6647934SMark.Phalan@Sun.COM pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
6657934SMark.Phalan@Sun.COM {
6667934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
6677934SMark.Phalan@Sun.COM 
6687934SMark.Phalan@Sun.COM     plgctx->dh_1024 = DH_new();
6697934SMark.Phalan@Sun.COM     if (plgctx->dh_1024 == NULL)
6707934SMark.Phalan@Sun.COM 	goto cleanup;
6717934SMark.Phalan@Sun.COM     plgctx->dh_1024->p = BN_bin2bn(pkinit_1024_dhprime,
6727934SMark.Phalan@Sun.COM 	sizeof(pkinit_1024_dhprime), NULL);
6737934SMark.Phalan@Sun.COM     if ((plgctx->dh_1024->g = BN_new()) == NULL ||
6747934SMark.Phalan@Sun.COM 	(plgctx->dh_1024->q = BN_new()) == NULL)
6757934SMark.Phalan@Sun.COM 	goto cleanup;
6767934SMark.Phalan@Sun.COM     BN_set_word(plgctx->dh_1024->g, DH_GENERATOR_2);
6777934SMark.Phalan@Sun.COM     BN_rshift1(plgctx->dh_1024->q, plgctx->dh_1024->p);
6787934SMark.Phalan@Sun.COM 
6797934SMark.Phalan@Sun.COM     plgctx->dh_2048 = DH_new();
6807934SMark.Phalan@Sun.COM     if (plgctx->dh_2048 == NULL)
6817934SMark.Phalan@Sun.COM 	goto cleanup;
6827934SMark.Phalan@Sun.COM     plgctx->dh_2048->p = BN_bin2bn(pkinit_2048_dhprime,
6837934SMark.Phalan@Sun.COM 	sizeof(pkinit_2048_dhprime), NULL);
6847934SMark.Phalan@Sun.COM     if ((plgctx->dh_2048->g = BN_new()) == NULL ||
6857934SMark.Phalan@Sun.COM 	(plgctx->dh_2048->q = BN_new()) == NULL)
6867934SMark.Phalan@Sun.COM 	goto cleanup;
6877934SMark.Phalan@Sun.COM     BN_set_word(plgctx->dh_2048->g, DH_GENERATOR_2);
6887934SMark.Phalan@Sun.COM     BN_rshift1(plgctx->dh_2048->q, plgctx->dh_2048->p);
6897934SMark.Phalan@Sun.COM 
6907934SMark.Phalan@Sun.COM     plgctx->dh_4096 = DH_new();
6917934SMark.Phalan@Sun.COM     if (plgctx->dh_4096 == NULL)
6927934SMark.Phalan@Sun.COM 	goto cleanup;
6937934SMark.Phalan@Sun.COM     plgctx->dh_4096->p = BN_bin2bn(pkinit_4096_dhprime,
6947934SMark.Phalan@Sun.COM 	sizeof(pkinit_4096_dhprime), NULL);
6957934SMark.Phalan@Sun.COM     if ((plgctx->dh_4096->g = BN_new()) == NULL ||
6967934SMark.Phalan@Sun.COM 	(plgctx->dh_4096->q = BN_new()) == NULL)
6977934SMark.Phalan@Sun.COM 	goto cleanup;
6987934SMark.Phalan@Sun.COM     BN_set_word(plgctx->dh_4096->g, DH_GENERATOR_2);
6997934SMark.Phalan@Sun.COM     BN_rshift1(plgctx->dh_4096->q, plgctx->dh_4096->p);
7007934SMark.Phalan@Sun.COM 
7017934SMark.Phalan@Sun.COM     retval = 0;
7027934SMark.Phalan@Sun.COM 
7037934SMark.Phalan@Sun.COM cleanup:
7047934SMark.Phalan@Sun.COM     if (retval)
7057934SMark.Phalan@Sun.COM 	pkinit_fini_dh_params(plgctx);
7067934SMark.Phalan@Sun.COM 
7077934SMark.Phalan@Sun.COM     return retval;
7087934SMark.Phalan@Sun.COM }
7097934SMark.Phalan@Sun.COM 
7107934SMark.Phalan@Sun.COM static void
pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)7117934SMark.Phalan@Sun.COM pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
7127934SMark.Phalan@Sun.COM {
7137934SMark.Phalan@Sun.COM     if (plgctx->dh_1024 != NULL)
7147934SMark.Phalan@Sun.COM 	DH_free(plgctx->dh_1024);
7157934SMark.Phalan@Sun.COM     if (plgctx->dh_2048 != NULL)
7167934SMark.Phalan@Sun.COM 	DH_free(plgctx->dh_2048);
7177934SMark.Phalan@Sun.COM     if (plgctx->dh_4096 != NULL)
7187934SMark.Phalan@Sun.COM 	DH_free(plgctx->dh_4096);
7197934SMark.Phalan@Sun.COM 
7207934SMark.Phalan@Sun.COM     plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
7217934SMark.Phalan@Sun.COM }
7227934SMark.Phalan@Sun.COM 
7237934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_init_certs(pkinit_identity_crypto_context ctx)7247934SMark.Phalan@Sun.COM pkinit_init_certs(pkinit_identity_crypto_context ctx)
7257934SMark.Phalan@Sun.COM {
7267934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
7277934SMark.Phalan@Sun.COM     int i;
7287934SMark.Phalan@Sun.COM 
7297934SMark.Phalan@Sun.COM     for (i = 0; i < MAX_CREDS_ALLOWED; i++)
7307934SMark.Phalan@Sun.COM 	ctx->creds[i] = NULL;
7317934SMark.Phalan@Sun.COM     ctx->my_certs = NULL;
7327934SMark.Phalan@Sun.COM     ctx->cert_index = 0;
7337934SMark.Phalan@Sun.COM     ctx->my_key = NULL;
7347934SMark.Phalan@Sun.COM     ctx->trustedCAs = NULL;
7357934SMark.Phalan@Sun.COM     ctx->intermediateCAs = NULL;
7367934SMark.Phalan@Sun.COM     ctx->revoked = NULL;
7377934SMark.Phalan@Sun.COM 
7387934SMark.Phalan@Sun.COM     return 0;
7397934SMark.Phalan@Sun.COM }
7407934SMark.Phalan@Sun.COM 
7417934SMark.Phalan@Sun.COM static void
pkinit_fini_certs(pkinit_identity_crypto_context ctx)7427934SMark.Phalan@Sun.COM pkinit_fini_certs(pkinit_identity_crypto_context ctx)
7437934SMark.Phalan@Sun.COM {
7447934SMark.Phalan@Sun.COM     if (ctx == NULL)
7457934SMark.Phalan@Sun.COM 	return;
7467934SMark.Phalan@Sun.COM 
7477934SMark.Phalan@Sun.COM     if (ctx->my_certs != NULL)
7487934SMark.Phalan@Sun.COM 	sk_X509_pop_free(ctx->my_certs, X509_free);
7497934SMark.Phalan@Sun.COM 
7507934SMark.Phalan@Sun.COM     if (ctx->my_key != NULL)
7517934SMark.Phalan@Sun.COM 	EVP_PKEY_free(ctx->my_key);
7527934SMark.Phalan@Sun.COM 
7537934SMark.Phalan@Sun.COM     if (ctx->trustedCAs != NULL)
7547934SMark.Phalan@Sun.COM 	sk_X509_pop_free(ctx->trustedCAs, X509_free);
7557934SMark.Phalan@Sun.COM 
7567934SMark.Phalan@Sun.COM     if (ctx->intermediateCAs != NULL)
7577934SMark.Phalan@Sun.COM 	sk_X509_pop_free(ctx->intermediateCAs, X509_free);
7587934SMark.Phalan@Sun.COM 
7597934SMark.Phalan@Sun.COM     if (ctx->revoked != NULL)
7607934SMark.Phalan@Sun.COM 	sk_X509_CRL_pop_free(ctx->revoked, X509_CRL_free);
7617934SMark.Phalan@Sun.COM }
7627934SMark.Phalan@Sun.COM 
7637934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)7647934SMark.Phalan@Sun.COM pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)
7657934SMark.Phalan@Sun.COM {
7667934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
7677934SMark.Phalan@Sun.COM 
7687934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
7697934SMark.Phalan@Sun.COM     ctx->p11_module_name = strdup(PKCS11_MODNAME);
7707934SMark.Phalan@Sun.COM     if (ctx->p11_module_name == NULL)
7717934SMark.Phalan@Sun.COM 	return ENOMEM;
7727934SMark.Phalan@Sun.COM     ctx->p11_module = NULL;
7737934SMark.Phalan@Sun.COM     ctx->slotid = PK_NOSLOT;
7747934SMark.Phalan@Sun.COM     ctx->token_label = NULL;
7757934SMark.Phalan@Sun.COM     ctx->cert_label = NULL;
77612941Swill.fiveash@oracle.com     ctx->PIN = NULL;
7777934SMark.Phalan@Sun.COM     ctx->session = CK_INVALID_HANDLE;
7787934SMark.Phalan@Sun.COM     ctx->p11 = NULL;
77911781SWill.Fiveash@Sun.COM     ctx->p11flags = 0; /* Solaris Kerberos */
7807934SMark.Phalan@Sun.COM #endif
7817934SMark.Phalan@Sun.COM     ctx->pkcs11_method = 0;
782*12945Swill.fiveash@oracle.com     (void) memset(ctx->creds, 0, sizeof(ctx->creds));
7837934SMark.Phalan@Sun.COM 
7847934SMark.Phalan@Sun.COM     return 0;
7857934SMark.Phalan@Sun.COM }
7867934SMark.Phalan@Sun.COM 
7877934SMark.Phalan@Sun.COM static void
pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)7887934SMark.Phalan@Sun.COM pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
7897934SMark.Phalan@Sun.COM {
7907934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
7917934SMark.Phalan@Sun.COM     if (ctx == NULL)
7927934SMark.Phalan@Sun.COM 	return;
7937934SMark.Phalan@Sun.COM 
7947934SMark.Phalan@Sun.COM     if (ctx->p11 != NULL) {
795*12945Swill.fiveash@oracle.com 	if (ctx->session != CK_INVALID_HANDLE) {
7967934SMark.Phalan@Sun.COM 	    ctx->p11->C_CloseSession(ctx->session);
7977934SMark.Phalan@Sun.COM 	    ctx->session = CK_INVALID_HANDLE;
7987934SMark.Phalan@Sun.COM 	}
7997934SMark.Phalan@Sun.COM 	/*
8007934SMark.Phalan@Sun.COM 	 * Solaris Kerberos:
8017934SMark.Phalan@Sun.COM 	 * Only call C_Finalize if the process was not already using pkcs11.
8027934SMark.Phalan@Sun.COM 	 */
8037934SMark.Phalan@Sun.COM 	if (ctx->finalize_pkcs11 == TRUE)
8047934SMark.Phalan@Sun.COM 	    ctx->p11->C_Finalize(NULL_PTR);
8057934SMark.Phalan@Sun.COM 
8067934SMark.Phalan@Sun.COM 	ctx->p11 = NULL;
8077934SMark.Phalan@Sun.COM     }
8087934SMark.Phalan@Sun.COM     if (ctx->p11_module != NULL) {
8097934SMark.Phalan@Sun.COM 	pkinit_C_UnloadModule(ctx->p11_module);
8107934SMark.Phalan@Sun.COM 	ctx->p11_module = NULL;
8117934SMark.Phalan@Sun.COM     }
8127934SMark.Phalan@Sun.COM     if (ctx->p11_module_name != NULL)
8137934SMark.Phalan@Sun.COM 	free(ctx->p11_module_name);
8147934SMark.Phalan@Sun.COM     if (ctx->token_label != NULL)
8157934SMark.Phalan@Sun.COM 	free(ctx->token_label);
8167934SMark.Phalan@Sun.COM     if (ctx->cert_id != NULL)
8177934SMark.Phalan@Sun.COM 	free(ctx->cert_id);
8187934SMark.Phalan@Sun.COM     if (ctx->cert_label != NULL)
8197934SMark.Phalan@Sun.COM 	free(ctx->cert_label);
82012941Swill.fiveash@oracle.com     if (ctx->PIN != NULL) {
82112941Swill.fiveash@oracle.com 	(void) memset(ctx->PIN, 0, strlen(ctx->PIN));
82212941Swill.fiveash@oracle.com 	free(ctx->PIN);
82312941Swill.fiveash@oracle.com     }
8247934SMark.Phalan@Sun.COM #endif
8257934SMark.Phalan@Sun.COM }
8267934SMark.Phalan@Sun.COM 
8277934SMark.Phalan@Sun.COM krb5_error_code
pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,krb5_prompter_fct prompter,void * prompter_data)8287934SMark.Phalan@Sun.COM pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
8297934SMark.Phalan@Sun.COM 			     krb5_prompter_fct prompter,
8307934SMark.Phalan@Sun.COM 			     void *prompter_data)
8317934SMark.Phalan@Sun.COM {
8327934SMark.Phalan@Sun.COM     id_cryptoctx->prompter = prompter;
8337934SMark.Phalan@Sun.COM     id_cryptoctx->prompter_data = prompter_data;
8347934SMark.Phalan@Sun.COM 
8357934SMark.Phalan@Sun.COM     return 0;
8367934SMark.Phalan@Sun.COM }
8377934SMark.Phalan@Sun.COM 
8387934SMark.Phalan@Sun.COM /* ARGSUSED */
8397934SMark.Phalan@Sun.COM krb5_error_code
cms_signeddata_create(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int cms_msg_type,int include_certchain,unsigned char * data,unsigned int data_len,unsigned char ** signed_data,unsigned int * signed_data_len)8407934SMark.Phalan@Sun.COM cms_signeddata_create(krb5_context context,
8417934SMark.Phalan@Sun.COM 		      pkinit_plg_crypto_context plg_cryptoctx,
8427934SMark.Phalan@Sun.COM 		      pkinit_req_crypto_context req_cryptoctx,
8437934SMark.Phalan@Sun.COM 		      pkinit_identity_crypto_context id_cryptoctx,
8447934SMark.Phalan@Sun.COM 		      int cms_msg_type,
8457934SMark.Phalan@Sun.COM 		      int include_certchain,
8467934SMark.Phalan@Sun.COM 		      unsigned char *data,
8477934SMark.Phalan@Sun.COM 		      unsigned int data_len,
8487934SMark.Phalan@Sun.COM 		      unsigned char **signed_data,
8497934SMark.Phalan@Sun.COM 		      unsigned int *signed_data_len)
8507934SMark.Phalan@Sun.COM {
8517934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
8527934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
8537934SMark.Phalan@Sun.COM     PKCS7  *p7 = NULL, *inner_p7 = NULL;
8547934SMark.Phalan@Sun.COM     PKCS7_SIGNED *p7s = NULL;
8557934SMark.Phalan@Sun.COM     PKCS7_SIGNER_INFO *p7si = NULL;
8567934SMark.Phalan@Sun.COM     unsigned char *p;
8577934SMark.Phalan@Sun.COM     ASN1_TYPE *pkinit_data = NULL;
8587934SMark.Phalan@Sun.COM     STACK_OF(X509) * cert_stack = NULL;
8597934SMark.Phalan@Sun.COM     ASN1_OCTET_STRING *digest_attr = NULL;
8607934SMark.Phalan@Sun.COM     EVP_MD_CTX ctx, ctx2;
8617934SMark.Phalan@Sun.COM     const EVP_MD *md_tmp = NULL;
8627934SMark.Phalan@Sun.COM     unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
8637934SMark.Phalan@Sun.COM     unsigned char *digestInfo_buf = NULL, *abuf = NULL;
8647934SMark.Phalan@Sun.COM     unsigned int md_len, md_len2, alen, digestInfo_len;
8657934SMark.Phalan@Sun.COM     STACK_OF(X509_ATTRIBUTE) * sk;
8667934SMark.Phalan@Sun.COM     unsigned char *sig = NULL;
8677934SMark.Phalan@Sun.COM     unsigned int sig_len = 0;
8687934SMark.Phalan@Sun.COM     X509_ALGOR *alg = NULL;
8697934SMark.Phalan@Sun.COM     ASN1_OCTET_STRING *digest = NULL;
8707934SMark.Phalan@Sun.COM     unsigned int alg_len = 0, digest_len = 0;
8717934SMark.Phalan@Sun.COM     unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
8727934SMark.Phalan@Sun.COM     X509 *cert = NULL;
8737934SMark.Phalan@Sun.COM     ASN1_OBJECT *oid = NULL;
8747934SMark.Phalan@Sun.COM 
8757934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
8767934SMark.Phalan@Sun.COM     if (signed_data == NULL)
8777934SMark.Phalan@Sun.COM 	return EINVAL;
8787934SMark.Phalan@Sun.COM 
8797934SMark.Phalan@Sun.COM     if (signed_data_len == NULL)
8807934SMark.Phalan@Sun.COM 	return EINVAL;
8817934SMark.Phalan@Sun.COM 
8827934SMark.Phalan@Sun.COM     /* start creating PKCS7 data */
8837934SMark.Phalan@Sun.COM     if ((p7 = PKCS7_new()) == NULL)
8847934SMark.Phalan@Sun.COM 	goto cleanup;
8857934SMark.Phalan@Sun.COM     p7->type = OBJ_nid2obj(NID_pkcs7_signed);
8867934SMark.Phalan@Sun.COM 
8877934SMark.Phalan@Sun.COM     if ((p7s = PKCS7_SIGNED_new()) == NULL)
8887934SMark.Phalan@Sun.COM 	goto cleanup;
8897934SMark.Phalan@Sun.COM     p7->d.sign = p7s;
8907934SMark.Phalan@Sun.COM     if (!ASN1_INTEGER_set(p7s->version, 3))
8917934SMark.Phalan@Sun.COM 	goto cleanup;
8927934SMark.Phalan@Sun.COM 
8937934SMark.Phalan@Sun.COM     /* create a cert chain that has at least the signer's certificate */
8947934SMark.Phalan@Sun.COM     if ((cert_stack = sk_X509_new_null()) == NULL)
8957934SMark.Phalan@Sun.COM 	goto cleanup;
8967934SMark.Phalan@Sun.COM 
8977934SMark.Phalan@Sun.COM     cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
8987934SMark.Phalan@Sun.COM     if (!include_certchain) {
8997934SMark.Phalan@Sun.COM 	pkiDebug("only including signer's certificate\n");
9007934SMark.Phalan@Sun.COM 	sk_X509_push(cert_stack, X509_dup(cert));
9017934SMark.Phalan@Sun.COM     } else {
9027934SMark.Phalan@Sun.COM 	/* create a cert chain */
9037934SMark.Phalan@Sun.COM 	X509_STORE *certstore = NULL;
9047934SMark.Phalan@Sun.COM 	X509_STORE_CTX certctx;
9057934SMark.Phalan@Sun.COM 	STACK_OF(X509) *certstack = NULL;
9067934SMark.Phalan@Sun.COM 	char buf[DN_BUF_LEN];
9077934SMark.Phalan@Sun.COM 	int i = 0, size = 0;
9087934SMark.Phalan@Sun.COM 
9097934SMark.Phalan@Sun.COM 	if ((certstore = X509_STORE_new()) == NULL)
9107934SMark.Phalan@Sun.COM 	    goto cleanup;
9117934SMark.Phalan@Sun.COM 	pkiDebug("building certificate chain\n");
9127934SMark.Phalan@Sun.COM 	X509_STORE_set_verify_cb_func(certstore, openssl_callback);
9137934SMark.Phalan@Sun.COM 	X509_STORE_CTX_init(&certctx, certstore, cert,
9147934SMark.Phalan@Sun.COM 			    id_cryptoctx->intermediateCAs);
9157934SMark.Phalan@Sun.COM 	X509_STORE_CTX_trusted_stack(&certctx, id_cryptoctx->trustedCAs);
91611491SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
91711491SMark.Phalan@Sun.COM 	if (X509_verify_cert(&certctx) <= 0) {
9187934SMark.Phalan@Sun.COM 	    pkiDebug("failed to create a certificate chain: %s\n",
9197934SMark.Phalan@Sun.COM 	    X509_verify_cert_error_string(X509_STORE_CTX_get_error(&certctx)));
9207934SMark.Phalan@Sun.COM 	    if (!sk_X509_num(id_cryptoctx->trustedCAs))
9217934SMark.Phalan@Sun.COM 		pkiDebug("No trusted CAs found. Check your X509_anchors\n");
9227934SMark.Phalan@Sun.COM 	    goto cleanup;
9237934SMark.Phalan@Sun.COM 	}
9247934SMark.Phalan@Sun.COM 	certstack = X509_STORE_CTX_get1_chain(&certctx);
9257934SMark.Phalan@Sun.COM 	size = sk_X509_num(certstack);
9267934SMark.Phalan@Sun.COM 	pkiDebug("size of certificate chain = %d\n", size);
9277934SMark.Phalan@Sun.COM 	for(i = 0; i < size - 1; i++) {
9287934SMark.Phalan@Sun.COM 	    X509 *x = sk_X509_value(certstack, i);
9297934SMark.Phalan@Sun.COM 	    X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
9307934SMark.Phalan@Sun.COM 	    pkiDebug("cert #%d: %s\n", i, buf);
9317934SMark.Phalan@Sun.COM 	    sk_X509_push(cert_stack, X509_dup(x));
9327934SMark.Phalan@Sun.COM 	}
9337934SMark.Phalan@Sun.COM 	X509_STORE_CTX_cleanup(&certctx);
9347934SMark.Phalan@Sun.COM 	X509_STORE_free(certstore);
9357934SMark.Phalan@Sun.COM 	sk_X509_pop_free(certstack, X509_free);
9367934SMark.Phalan@Sun.COM     }
9377934SMark.Phalan@Sun.COM     p7s->cert = cert_stack;
9387934SMark.Phalan@Sun.COM 
9397934SMark.Phalan@Sun.COM     /* fill-in PKCS7_SIGNER_INFO */
9407934SMark.Phalan@Sun.COM     if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
9417934SMark.Phalan@Sun.COM 	goto cleanup;
9427934SMark.Phalan@Sun.COM     if (!ASN1_INTEGER_set(p7si->version, 1))
9437934SMark.Phalan@Sun.COM 	goto cleanup;
9447934SMark.Phalan@Sun.COM     if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
9457934SMark.Phalan@Sun.COM 		       X509_get_issuer_name(cert)))
9467934SMark.Phalan@Sun.COM 	goto cleanup;
9477934SMark.Phalan@Sun.COM     /* because ASN1_INTEGER_set is used to set a 'long' we will do
9487934SMark.Phalan@Sun.COM      * things the ugly way. */
9497934SMark.Phalan@Sun.COM     M_ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
9507934SMark.Phalan@Sun.COM     if (!(p7si->issuer_and_serial->serial =
9517934SMark.Phalan@Sun.COM 	  M_ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
9527934SMark.Phalan@Sun.COM 	goto cleanup;
9537934SMark.Phalan@Sun.COM 
9547934SMark.Phalan@Sun.COM     /* will not fill-out EVP_PKEY because it's on the smartcard */
9557934SMark.Phalan@Sun.COM 
9567934SMark.Phalan@Sun.COM     /* Set digest algs */
9577934SMark.Phalan@Sun.COM     p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
9587934SMark.Phalan@Sun.COM 
9597934SMark.Phalan@Sun.COM     if (p7si->digest_alg->parameter != NULL)
9607934SMark.Phalan@Sun.COM 	ASN1_TYPE_free(p7si->digest_alg->parameter);
9617934SMark.Phalan@Sun.COM     if ((p7si->digest_alg->parameter = ASN1_TYPE_new()) == NULL)
9627934SMark.Phalan@Sun.COM 	goto cleanup;
9637934SMark.Phalan@Sun.COM     p7si->digest_alg->parameter->type = V_ASN1_NULL;
9647934SMark.Phalan@Sun.COM 
9657934SMark.Phalan@Sun.COM     /* Set sig algs */
9667934SMark.Phalan@Sun.COM     if (p7si->digest_enc_alg->parameter != NULL)
9677934SMark.Phalan@Sun.COM 	ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
9687934SMark.Phalan@Sun.COM     p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
9697934SMark.Phalan@Sun.COM     if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
9707934SMark.Phalan@Sun.COM 	goto cleanup;
9717934SMark.Phalan@Sun.COM     p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
9727934SMark.Phalan@Sun.COM 
9737934SMark.Phalan@Sun.COM     /* pick the correct oid for the eContentInfo */
9747934SMark.Phalan@Sun.COM     oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
9757934SMark.Phalan@Sun.COM     if (oid == NULL)
9767934SMark.Phalan@Sun.COM 	goto cleanup;
9777934SMark.Phalan@Sun.COM 
9787934SMark.Phalan@Sun.COM     if (cms_msg_type == CMS_SIGN_DRAFT9) {
9797934SMark.Phalan@Sun.COM 	/* don't include signed attributes for pa-type 15 request */
9807934SMark.Phalan@Sun.COM 	abuf = data;
9817934SMark.Phalan@Sun.COM 	alen = data_len;
9827934SMark.Phalan@Sun.COM     } else {
9837934SMark.Phalan@Sun.COM 	/* add signed attributes */
9847934SMark.Phalan@Sun.COM 	/* compute sha1 digest over the EncapsulatedContentInfo */
9857934SMark.Phalan@Sun.COM 	EVP_MD_CTX_init(&ctx);
9867934SMark.Phalan@Sun.COM 	EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
9877934SMark.Phalan@Sun.COM 	EVP_DigestUpdate(&ctx, data, data_len);
9887934SMark.Phalan@Sun.COM 	md_tmp = EVP_MD_CTX_md(&ctx);
9897934SMark.Phalan@Sun.COM 	EVP_DigestFinal_ex(&ctx, md_data, &md_len);
9907934SMark.Phalan@Sun.COM 
9917934SMark.Phalan@Sun.COM 	/* create a message digest attr */
9927934SMark.Phalan@Sun.COM 	digest_attr = ASN1_OCTET_STRING_new();
9937934SMark.Phalan@Sun.COM 	ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
9947934SMark.Phalan@Sun.COM 	PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
9957934SMark.Phalan@Sun.COM 				   V_ASN1_OCTET_STRING, (char *) digest_attr);
9967934SMark.Phalan@Sun.COM 
9977934SMark.Phalan@Sun.COM 	/* create a content-type attr */
9987934SMark.Phalan@Sun.COM 	PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
9997934SMark.Phalan@Sun.COM 				   V_ASN1_OBJECT, oid);
10007934SMark.Phalan@Sun.COM 
10017934SMark.Phalan@Sun.COM 	/* create the signature over signed attributes. get DER encoded value */
10027934SMark.Phalan@Sun.COM 	/* This is the place where smartcard signature needs to be calculated */
10037934SMark.Phalan@Sun.COM 	sk = p7si->auth_attr;
10047934SMark.Phalan@Sun.COM 	alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
10057934SMark.Phalan@Sun.COM 			     ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
10067934SMark.Phalan@Sun.COM 	if (abuf == NULL)
10077934SMark.Phalan@Sun.COM 	    goto cleanup2;
10087934SMark.Phalan@Sun.COM     }
10097934SMark.Phalan@Sun.COM 
10107934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
10117934SMark.Phalan@Sun.COM     /* Some tokens can only do RSAEncryption without sha1 hash */
10127934SMark.Phalan@Sun.COM     /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
10137934SMark.Phalan@Sun.COM      * function and the hash value into an ASN.1 value of type DigestInfo
10147934SMark.Phalan@Sun.COM      * DigestInfo::=SEQUENCE {
10157934SMark.Phalan@Sun.COM      *	digestAlgorithm  AlgorithmIdentifier,
10167934SMark.Phalan@Sun.COM      *	digest OCTET STRING }
10177934SMark.Phalan@Sun.COM      */
10187934SMark.Phalan@Sun.COM     if (id_cryptoctx->pkcs11_method == 1 &&
10197934SMark.Phalan@Sun.COM 	    id_cryptoctx->mech == CKM_RSA_PKCS) {
10207934SMark.Phalan@Sun.COM 	pkiDebug("mech = CKM_RSA_PKCS\n");
10217934SMark.Phalan@Sun.COM 	EVP_MD_CTX_init(&ctx2);
10227934SMark.Phalan@Sun.COM 	/* if this is not draft9 request, include digest signed attribute */
10237934SMark.Phalan@Sun.COM 	if (cms_msg_type != CMS_SIGN_DRAFT9)
10247934SMark.Phalan@Sun.COM 	    EVP_DigestInit_ex(&ctx2, md_tmp, NULL);
10257934SMark.Phalan@Sun.COM 	else
10267934SMark.Phalan@Sun.COM 	    EVP_DigestInit_ex(&ctx2, EVP_sha1(), NULL);
10277934SMark.Phalan@Sun.COM 	EVP_DigestUpdate(&ctx2, abuf, alen);
10287934SMark.Phalan@Sun.COM 	EVP_DigestFinal_ex(&ctx2, md_data2, &md_len2);
10297934SMark.Phalan@Sun.COM 
10307934SMark.Phalan@Sun.COM 	alg = X509_ALGOR_new();
10317934SMark.Phalan@Sun.COM 	if (alg == NULL)
10327934SMark.Phalan@Sun.COM 	    goto cleanup2;
10337934SMark.Phalan@Sun.COM 	alg->algorithm = OBJ_nid2obj(NID_sha1);
10347934SMark.Phalan@Sun.COM 	alg->parameter = NULL;
10357934SMark.Phalan@Sun.COM 	alg_len = i2d_X509_ALGOR(alg, NULL);
10367934SMark.Phalan@Sun.COM 	alg_buf = (unsigned char *)malloc(alg_len);
10377934SMark.Phalan@Sun.COM 	if (alg_buf == NULL)
10387934SMark.Phalan@Sun.COM 	    goto cleanup2;
10397934SMark.Phalan@Sun.COM 
10407934SMark.Phalan@Sun.COM 	digest = ASN1_OCTET_STRING_new();
10417934SMark.Phalan@Sun.COM 	if (digest == NULL)
10427934SMark.Phalan@Sun.COM 	    goto cleanup2;
10437934SMark.Phalan@Sun.COM 	ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
10447934SMark.Phalan@Sun.COM 	digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
10457934SMark.Phalan@Sun.COM 	digest_buf = (unsigned char *)malloc(digest_len);
10467934SMark.Phalan@Sun.COM 	if (digest_buf == NULL)
10477934SMark.Phalan@Sun.COM 	    goto cleanup2;
10487934SMark.Phalan@Sun.COM 
10497934SMark.Phalan@Sun.COM 	digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
10507934SMark.Phalan@Sun.COM 					  V_ASN1_SEQUENCE);
10517934SMark.Phalan@Sun.COM 	y = digestInfo_buf = (unsigned char *)malloc(digestInfo_len);
10527934SMark.Phalan@Sun.COM 	if (digestInfo_buf == NULL)
10537934SMark.Phalan@Sun.COM 	    goto cleanup2;
10547934SMark.Phalan@Sun.COM 	ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
10557934SMark.Phalan@Sun.COM 			V_ASN1_UNIVERSAL);
10567934SMark.Phalan@Sun.COM 	i2d_X509_ALGOR(alg, &y);
10577934SMark.Phalan@Sun.COM 	i2d_ASN1_OCTET_STRING(digest, &y);
10587934SMark.Phalan@Sun.COM #ifdef DEBUG_SIG
10597934SMark.Phalan@Sun.COM 	pkiDebug("signing buffer\n");
10607934SMark.Phalan@Sun.COM 	print_buffer(digestInfo_buf, digestInfo_len);
10617934SMark.Phalan@Sun.COM 	print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
10627934SMark.Phalan@Sun.COM #endif
10637934SMark.Phalan@Sun.COM 	retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
10647934SMark.Phalan@Sun.COM 				  digestInfo_len, &sig, &sig_len);
10657934SMark.Phalan@Sun.COM     } else
10667934SMark.Phalan@Sun.COM #endif
10677934SMark.Phalan@Sun.COM     {
10687934SMark.Phalan@Sun.COM 	pkiDebug("mech = %s\n",
10697934SMark.Phalan@Sun.COM 	    id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
10707934SMark.Phalan@Sun.COM 	retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
10717934SMark.Phalan@Sun.COM 				  &sig, &sig_len);
10727934SMark.Phalan@Sun.COM     }
10737934SMark.Phalan@Sun.COM #ifdef DEBUG_SIG
10747934SMark.Phalan@Sun.COM     print_buffer(sig, sig_len);
10757934SMark.Phalan@Sun.COM #endif
10767934SMark.Phalan@Sun.COM     if (cms_msg_type != CMS_SIGN_DRAFT9)
10777934SMark.Phalan@Sun.COM 	free(abuf);
10787934SMark.Phalan@Sun.COM     if (retval)
10797934SMark.Phalan@Sun.COM 	goto cleanup2;
10807934SMark.Phalan@Sun.COM 
10817934SMark.Phalan@Sun.COM     /* Add signature */
10827934SMark.Phalan@Sun.COM     if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig,
10837934SMark.Phalan@Sun.COM 			 (int)sig_len)) {
10847934SMark.Phalan@Sun.COM 	unsigned long err = ERR_peek_error();
10857934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
10867934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "%s\n",
10877934SMark.Phalan@Sun.COM 			       ERR_error_string(err, NULL));
10887934SMark.Phalan@Sun.COM 	pkiDebug("failed to add a signed digest attribute\n");
10897934SMark.Phalan@Sun.COM 	goto cleanup2;
10907934SMark.Phalan@Sun.COM     }
10917934SMark.Phalan@Sun.COM     /* adder signer_info to pkcs7 signed */
10927934SMark.Phalan@Sun.COM     if (!PKCS7_add_signer(p7, p7si))
10937934SMark.Phalan@Sun.COM 	goto cleanup2;
10947934SMark.Phalan@Sun.COM 
10957934SMark.Phalan@Sun.COM     /* start on adding data to the pkcs7 signed */
10967934SMark.Phalan@Sun.COM     if ((inner_p7 = PKCS7_new()) == NULL)
10977934SMark.Phalan@Sun.COM 	goto cleanup2;
10987934SMark.Phalan@Sun.COM     if ((pkinit_data = ASN1_TYPE_new()) == NULL)
10997934SMark.Phalan@Sun.COM 	goto cleanup2;
11007934SMark.Phalan@Sun.COM     pkinit_data->type = V_ASN1_OCTET_STRING;
11017934SMark.Phalan@Sun.COM     if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
11027934SMark.Phalan@Sun.COM 	goto cleanup2;
11037934SMark.Phalan@Sun.COM     if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
11047934SMark.Phalan@Sun.COM 			       (int)data_len)) {
11057934SMark.Phalan@Sun.COM 	unsigned long err = ERR_peek_error();
11067934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
11077934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "%s\n",
11087934SMark.Phalan@Sun.COM 			       ERR_error_string(err, NULL));
11097934SMark.Phalan@Sun.COM 	pkiDebug("failed to add pkcs7 data\n");
11107934SMark.Phalan@Sun.COM 	goto cleanup2;
11117934SMark.Phalan@Sun.COM     }
11127934SMark.Phalan@Sun.COM 
11137934SMark.Phalan@Sun.COM     if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
11147934SMark.Phalan@Sun.COM 	goto cleanup2;
11157934SMark.Phalan@Sun.COM 
11167934SMark.Phalan@Sun.COM     if (p7s->contents != NULL)
11177934SMark.Phalan@Sun.COM 	PKCS7_free(p7s->contents);
11187934SMark.Phalan@Sun.COM     p7s->contents = inner_p7;
11197934SMark.Phalan@Sun.COM 
11207934SMark.Phalan@Sun.COM     *signed_data_len = i2d_PKCS7(p7, NULL);
11217934SMark.Phalan@Sun.COM     if (!(*signed_data_len)) {
11227934SMark.Phalan@Sun.COM 	unsigned long err = ERR_peek_error();
11237934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
11247934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "%s\n",
11257934SMark.Phalan@Sun.COM 			       ERR_error_string(err, NULL));
11267934SMark.Phalan@Sun.COM 	pkiDebug("failed to der encode pkcs7\n");
11277934SMark.Phalan@Sun.COM 	goto cleanup2;
11287934SMark.Phalan@Sun.COM     }
11297934SMark.Phalan@Sun.COM     if ((p = *signed_data =
11307934SMark.Phalan@Sun.COM 	 (unsigned char *) malloc((size_t)*signed_data_len)) == NULL)
11317934SMark.Phalan@Sun.COM 	goto cleanup2;
11327934SMark.Phalan@Sun.COM 
11337934SMark.Phalan@Sun.COM     /* DER encode PKCS7 data */
11347934SMark.Phalan@Sun.COM     retval = i2d_PKCS7(p7, &p);
11357934SMark.Phalan@Sun.COM     if (!retval) {
11367934SMark.Phalan@Sun.COM 	unsigned long err = ERR_peek_error();
11377934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
11387934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "%s\n",
11397934SMark.Phalan@Sun.COM 			       ERR_error_string(err, NULL));
11407934SMark.Phalan@Sun.COM 	pkiDebug("failed to der encode pkcs7\n");
11417934SMark.Phalan@Sun.COM 	goto cleanup2;
11427934SMark.Phalan@Sun.COM     }
11437934SMark.Phalan@Sun.COM     retval = 0;
11447934SMark.Phalan@Sun.COM 
11457934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
11467934SMark.Phalan@Sun.COM     if (cms_msg_type == CMS_SIGN_CLIENT) {
11477934SMark.Phalan@Sun.COM 	print_buffer_bin(*signed_data, *signed_data_len,
11487934SMark.Phalan@Sun.COM 			 "/tmp/client_pkcs7_signeddata");
11497934SMark.Phalan@Sun.COM     } else {
11507934SMark.Phalan@Sun.COM 	if (cms_msg_type == CMS_SIGN_SERVER) {
11517934SMark.Phalan@Sun.COM 	    print_buffer_bin(*signed_data, *signed_data_len,
11527934SMark.Phalan@Sun.COM 			     "/tmp/kdc_pkcs7_signeddata");
11537934SMark.Phalan@Sun.COM 	} else {
11547934SMark.Phalan@Sun.COM 	    print_buffer_bin(*signed_data, *signed_data_len,
11557934SMark.Phalan@Sun.COM 			     "/tmp/draft9_pkcs7_signeddata");
11567934SMark.Phalan@Sun.COM 	}
11577934SMark.Phalan@Sun.COM     }
11587934SMark.Phalan@Sun.COM #endif
11597934SMark.Phalan@Sun.COM 
11607934SMark.Phalan@Sun.COM   cleanup2:
11617934SMark.Phalan@Sun.COM     if (cms_msg_type != CMS_SIGN_DRAFT9)
11627934SMark.Phalan@Sun.COM 	EVP_MD_CTX_cleanup(&ctx);
11637934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
11647934SMark.Phalan@Sun.COM     if (id_cryptoctx->pkcs11_method == 1 &&
11657934SMark.Phalan@Sun.COM 	    id_cryptoctx->mech == CKM_RSA_PKCS) {
11667934SMark.Phalan@Sun.COM 	EVP_MD_CTX_cleanup(&ctx2);
11677934SMark.Phalan@Sun.COM 	if (digest_buf != NULL)
11687934SMark.Phalan@Sun.COM 	    free(digest_buf);
11697934SMark.Phalan@Sun.COM 	if (digestInfo_buf != NULL)
11707934SMark.Phalan@Sun.COM 	    free(digestInfo_buf);
11717934SMark.Phalan@Sun.COM 	if (alg_buf != NULL)
11727934SMark.Phalan@Sun.COM 	    free(alg_buf);
11737934SMark.Phalan@Sun.COM 	if (digest != NULL)
11747934SMark.Phalan@Sun.COM 	    ASN1_OCTET_STRING_free(digest);
11757934SMark.Phalan@Sun.COM     }
11767934SMark.Phalan@Sun.COM #endif
11777934SMark.Phalan@Sun.COM     if (alg != NULL)
11787934SMark.Phalan@Sun.COM 	X509_ALGOR_free(alg);
11797934SMark.Phalan@Sun.COM   cleanup:
11807934SMark.Phalan@Sun.COM     if (p7 != NULL)
11817934SMark.Phalan@Sun.COM 	PKCS7_free(p7);
11827934SMark.Phalan@Sun.COM     if (sig != NULL)
11837934SMark.Phalan@Sun.COM 	free(sig);
11847934SMark.Phalan@Sun.COM 
11857934SMark.Phalan@Sun.COM     return retval;
11867934SMark.Phalan@Sun.COM }
11877934SMark.Phalan@Sun.COM 
11887934SMark.Phalan@Sun.COM krb5_error_code
cms_signeddata_verify(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,int cms_msg_type,int require_crl_checking,unsigned char * signed_data,unsigned int signed_data_len,unsigned char ** data,unsigned int * data_len,unsigned char ** authz_data,unsigned int * authz_data_len)11897934SMark.Phalan@Sun.COM cms_signeddata_verify(krb5_context context,
11907934SMark.Phalan@Sun.COM 		      pkinit_plg_crypto_context plgctx,
11917934SMark.Phalan@Sun.COM 		      pkinit_req_crypto_context reqctx,
11927934SMark.Phalan@Sun.COM 		      pkinit_identity_crypto_context idctx,
11937934SMark.Phalan@Sun.COM 		      int cms_msg_type,
11947934SMark.Phalan@Sun.COM 		      int require_crl_checking,
11957934SMark.Phalan@Sun.COM 		      unsigned char *signed_data,
11967934SMark.Phalan@Sun.COM 		      unsigned int signed_data_len,
11977934SMark.Phalan@Sun.COM 		      unsigned char **data,
11987934SMark.Phalan@Sun.COM 		      unsigned int *data_len,
11997934SMark.Phalan@Sun.COM 		      unsigned char **authz_data,
12007934SMark.Phalan@Sun.COM 		      unsigned int *authz_data_len)
12017934SMark.Phalan@Sun.COM {
12027934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
12037934SMark.Phalan@Sun.COM     PKCS7 *p7 = NULL;
12047934SMark.Phalan@Sun.COM     BIO *out = NULL;
12057934SMark.Phalan@Sun.COM     int flags = PKCS7_NOVERIFY, i = 0;
12067934SMark.Phalan@Sun.COM     unsigned int vflags = 0, size = 0;
12077934SMark.Phalan@Sun.COM     const unsigned char *p = signed_data;
12087934SMark.Phalan@Sun.COM     STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
12097934SMark.Phalan@Sun.COM     PKCS7_SIGNER_INFO *si = NULL;
12107934SMark.Phalan@Sun.COM     X509 *x = NULL;
12117934SMark.Phalan@Sun.COM     X509_STORE *store = NULL;
12127934SMark.Phalan@Sun.COM     X509_STORE_CTX cert_ctx;
12137934SMark.Phalan@Sun.COM     STACK_OF(X509) *intermediateCAs = NULL;
12147934SMark.Phalan@Sun.COM     STACK_OF(X509_CRL) *revoked = NULL;
12157934SMark.Phalan@Sun.COM     STACK_OF(X509) *verified_chain = NULL;
12167934SMark.Phalan@Sun.COM     ASN1_OBJECT *oid = NULL;
12177934SMark.Phalan@Sun.COM     krb5_external_principal_identifier **krb5_verified_chain = NULL;
12187934SMark.Phalan@Sun.COM     krb5_data *authz = NULL;
12197934SMark.Phalan@Sun.COM     char buf[DN_BUF_LEN];
12207934SMark.Phalan@Sun.COM 
12217934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
12227934SMark.Phalan@Sun.COM     print_buffer_bin(signed_data, signed_data_len,
12237934SMark.Phalan@Sun.COM 		     "/tmp/client_received_pkcs7_signeddata");
12247934SMark.Phalan@Sun.COM #endif
12257934SMark.Phalan@Sun.COM 
12267934SMark.Phalan@Sun.COM     /* Do this early enough to create the shadow OID for pkcs7-data if needed */
12277934SMark.Phalan@Sun.COM     oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
12287934SMark.Phalan@Sun.COM     if (oid == NULL)
12297934SMark.Phalan@Sun.COM 	goto cleanup;
12307934SMark.Phalan@Sun.COM 
12317934SMark.Phalan@Sun.COM     /* decode received PKCS7 message */
12327934SMark.Phalan@Sun.COM     if ((p7 = d2i_PKCS7(NULL, &p, (int)signed_data_len)) == NULL) {
12337934SMark.Phalan@Sun.COM 	unsigned long err = ERR_peek_error();
12347934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "%s\n",
12357934SMark.Phalan@Sun.COM 			       ERR_error_string(err, NULL));
12367934SMark.Phalan@Sun.COM 	pkiDebug("%s: failed to decode message: %s\n",
12377934SMark.Phalan@Sun.COM 		 __FUNCTION__, ERR_error_string(err, NULL));
12387934SMark.Phalan@Sun.COM 	goto cleanup;
12397934SMark.Phalan@Sun.COM     }
12407934SMark.Phalan@Sun.COM 
12417934SMark.Phalan@Sun.COM     /* verify that the received message is PKCS7 SignedData message */
12427934SMark.Phalan@Sun.COM     if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
12437934SMark.Phalan@Sun.COM 	pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
12447934SMark.Phalan@Sun.COM 		 OBJ_obj2nid(p7->type));
12457934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "wrong oid\n");
12467934SMark.Phalan@Sun.COM 	goto cleanup;
12477934SMark.Phalan@Sun.COM     }
12487934SMark.Phalan@Sun.COM 
12497934SMark.Phalan@Sun.COM     /* setup to verify X509 certificate used to sign PKCS7 message */
12507934SMark.Phalan@Sun.COM     if (!(store = X509_STORE_new()))
12517934SMark.Phalan@Sun.COM 	goto cleanup;
12527934SMark.Phalan@Sun.COM 
12537934SMark.Phalan@Sun.COM     /* check if we are inforcing CRL checking */
12547934SMark.Phalan@Sun.COM     vflags = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
12557934SMark.Phalan@Sun.COM     if (require_crl_checking)
12567934SMark.Phalan@Sun.COM 	X509_STORE_set_verify_cb_func(store, openssl_callback);
12577934SMark.Phalan@Sun.COM     else
12587934SMark.Phalan@Sun.COM 	X509_STORE_set_verify_cb_func(store, openssl_callback_ignore_crls);
12597934SMark.Phalan@Sun.COM     X509_STORE_set_flags(store, vflags);
12607934SMark.Phalan@Sun.COM 
12617934SMark.Phalan@Sun.COM     /* get the signer's information from the PKCS7 message */
12627934SMark.Phalan@Sun.COM     if ((si_sk = PKCS7_get_signer_info(p7)) == NULL)
12637934SMark.Phalan@Sun.COM 	goto cleanup;
12647934SMark.Phalan@Sun.COM     if ((si = sk_PKCS7_SIGNER_INFO_value(si_sk, 0)) == NULL)
12657934SMark.Phalan@Sun.COM 	goto cleanup;
12667934SMark.Phalan@Sun.COM     if ((x = PKCS7_cert_from_signer_info(p7, si)) == NULL)
12677934SMark.Phalan@Sun.COM 	goto cleanup;
12687934SMark.Phalan@Sun.COM 
12697934SMark.Phalan@Sun.COM     /* create available CRL information (get local CRLs and include CRLs
12707934SMark.Phalan@Sun.COM      * received in the PKCS7 message
12717934SMark.Phalan@Sun.COM      */
12727934SMark.Phalan@Sun.COM     if (idctx->revoked == NULL)
12737934SMark.Phalan@Sun.COM 	revoked = p7->d.sign->crl;
12747934SMark.Phalan@Sun.COM     else if (p7->d.sign->crl == NULL)
12757934SMark.Phalan@Sun.COM 	revoked = idctx->revoked;
12767934SMark.Phalan@Sun.COM     else {
12777934SMark.Phalan@Sun.COM 	size = sk_X509_CRL_num(idctx->revoked);
12787934SMark.Phalan@Sun.COM 	revoked = sk_X509_CRL_new_null();
12797934SMark.Phalan@Sun.COM 	for (i = 0; i < size; i++)
12807934SMark.Phalan@Sun.COM 	    sk_X509_CRL_push(revoked, sk_X509_CRL_value(idctx->revoked, i));
12817934SMark.Phalan@Sun.COM 	size = sk_X509_num(p7->d.sign->crl);
12827934SMark.Phalan@Sun.COM 	for (i = 0; i < size; i++)
12837934SMark.Phalan@Sun.COM 	    sk_X509_CRL_push(revoked, sk_X509_CRL_value(p7->d.sign->crl, i));
12847934SMark.Phalan@Sun.COM     }
12857934SMark.Phalan@Sun.COM 
12867934SMark.Phalan@Sun.COM     /* create available intermediate CAs chains (get local intermediateCAs and
12877934SMark.Phalan@Sun.COM      * include the CA chain received in the PKCS7 message
12887934SMark.Phalan@Sun.COM      */
12897934SMark.Phalan@Sun.COM     if (idctx->intermediateCAs == NULL)
12907934SMark.Phalan@Sun.COM 	intermediateCAs = p7->d.sign->cert;
12917934SMark.Phalan@Sun.COM     else if (p7->d.sign->cert == NULL)
12927934SMark.Phalan@Sun.COM 	intermediateCAs = idctx->intermediateCAs;
12937934SMark.Phalan@Sun.COM     else {
12947934SMark.Phalan@Sun.COM 	size = sk_X509_num(idctx->intermediateCAs);
12957934SMark.Phalan@Sun.COM 	intermediateCAs = sk_X509_new_null();
12967934SMark.Phalan@Sun.COM 	for (i = 0; i < size; i++) {
12977934SMark.Phalan@Sun.COM 	    sk_X509_push(intermediateCAs,
12987934SMark.Phalan@Sun.COM 		sk_X509_value(idctx->intermediateCAs, i));
12997934SMark.Phalan@Sun.COM 	}
13007934SMark.Phalan@Sun.COM 	size = sk_X509_num(p7->d.sign->cert);
13017934SMark.Phalan@Sun.COM 	for (i = 0; i < size; i++) {
13027934SMark.Phalan@Sun.COM 	    sk_X509_push(intermediateCAs, sk_X509_value(p7->d.sign->cert, i));
13037934SMark.Phalan@Sun.COM 	}
13047934SMark.Phalan@Sun.COM     }
13057934SMark.Phalan@Sun.COM 
13067934SMark.Phalan@Sun.COM     /* initialize x509 context with the received certificate and
13077934SMark.Phalan@Sun.COM      * trusted and intermediate CA chains and CRLs
13087934SMark.Phalan@Sun.COM      */
13097934SMark.Phalan@Sun.COM     if (!X509_STORE_CTX_init(&cert_ctx, store, x, intermediateCAs))
13107934SMark.Phalan@Sun.COM 	goto cleanup;
13117934SMark.Phalan@Sun.COM 
13127934SMark.Phalan@Sun.COM     X509_STORE_CTX_set0_crls(&cert_ctx, revoked);
13137934SMark.Phalan@Sun.COM 
13147934SMark.Phalan@Sun.COM     /* add trusted CAs certificates for cert verification */
13157934SMark.Phalan@Sun.COM     if (idctx->trustedCAs != NULL)
13167934SMark.Phalan@Sun.COM 	X509_STORE_CTX_trusted_stack(&cert_ctx, idctx->trustedCAs);
13177934SMark.Phalan@Sun.COM     else {
13187934SMark.Phalan@Sun.COM 	pkiDebug("unable to find any trusted CAs\n");
13197934SMark.Phalan@Sun.COM 	goto cleanup;
13207934SMark.Phalan@Sun.COM     }
13217934SMark.Phalan@Sun.COM #ifdef DEBUG_CERTCHAIN
13227934SMark.Phalan@Sun.COM     if (intermediateCAs != NULL) {
13237934SMark.Phalan@Sun.COM 	size = sk_X509_num(intermediateCAs);
13247934SMark.Phalan@Sun.COM 	pkiDebug("untrusted cert chain of size %d\n", size);
13257934SMark.Phalan@Sun.COM 	for (i = 0; i < size; i++) {
13267934SMark.Phalan@Sun.COM 	    X509_NAME_oneline(X509_get_subject_name(
13277934SMark.Phalan@Sun.COM 		sk_X509_value(intermediateCAs, i)), buf, sizeof(buf));
13287934SMark.Phalan@Sun.COM 	    pkiDebug("cert #%d: %s\n", i, buf);
13297934SMark.Phalan@Sun.COM 	}
13307934SMark.Phalan@Sun.COM     }
13317934SMark.Phalan@Sun.COM     if (idctx->trustedCAs != NULL) {
13327934SMark.Phalan@Sun.COM 	size = sk_X509_num(idctx->trustedCAs);
13337934SMark.Phalan@Sun.COM 	pkiDebug("trusted cert chain of size %d\n", size);
13347934SMark.Phalan@Sun.COM 	for (i = 0; i < size; i++) {
13357934SMark.Phalan@Sun.COM 	    X509_NAME_oneline(X509_get_subject_name(
13367934SMark.Phalan@Sun.COM 		sk_X509_value(idctx->trustedCAs, i)), buf, sizeof(buf));
13377934SMark.Phalan@Sun.COM 	    pkiDebug("cert #%d: %s\n", i, buf);
13387934SMark.Phalan@Sun.COM 	}
13397934SMark.Phalan@Sun.COM     }
13407934SMark.Phalan@Sun.COM     if (revoked != NULL) {
13417934SMark.Phalan@Sun.COM 	size = sk_X509_CRL_num(revoked);
13427934SMark.Phalan@Sun.COM 	pkiDebug("CRL chain of size %d\n", size);
13437934SMark.Phalan@Sun.COM 	for (i = 0; i < size; i++) {
13447934SMark.Phalan@Sun.COM 	    X509_CRL *crl = sk_X509_CRL_value(revoked, i);
13457934SMark.Phalan@Sun.COM 	    X509_NAME_oneline(X509_CRL_get_issuer(crl), buf, sizeof(buf));
13467934SMark.Phalan@Sun.COM 	    pkiDebug("crls by CA #%d: %s\n", i , buf);
13477934SMark.Phalan@Sun.COM 	}
13487934SMark.Phalan@Sun.COM     }
13497934SMark.Phalan@Sun.COM #endif
13507934SMark.Phalan@Sun.COM 
13517934SMark.Phalan@Sun.COM     i = X509_verify_cert(&cert_ctx);
13527934SMark.Phalan@Sun.COM     if (i <= 0) {
13537934SMark.Phalan@Sun.COM 	int j = X509_STORE_CTX_get_error(&cert_ctx);
13547934SMark.Phalan@Sun.COM 
13557934SMark.Phalan@Sun.COM 	reqctx->received_cert = X509_dup(cert_ctx.current_cert);
13567934SMark.Phalan@Sun.COM 	switch(j) {
13577934SMark.Phalan@Sun.COM 	    case X509_V_ERR_CERT_REVOKED:
13587934SMark.Phalan@Sun.COM 		retval = KRB5KDC_ERR_REVOKED_CERTIFICATE;
13597934SMark.Phalan@Sun.COM 		break;
13607934SMark.Phalan@Sun.COM 	    case X509_V_ERR_UNABLE_TO_GET_CRL:
13617934SMark.Phalan@Sun.COM 		retval = KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN;
13627934SMark.Phalan@Sun.COM 		break;
13637934SMark.Phalan@Sun.COM 	    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
13647934SMark.Phalan@Sun.COM 	    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
13657934SMark.Phalan@Sun.COM 		retval = KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE;
13667934SMark.Phalan@Sun.COM 		break;
13677934SMark.Phalan@Sun.COM 	    default:
13687934SMark.Phalan@Sun.COM 		retval = KRB5KDC_ERR_INVALID_CERTIFICATE;
13697934SMark.Phalan@Sun.COM 	}
13707934SMark.Phalan@Sun.COM 	X509_NAME_oneline(X509_get_subject_name(
13717934SMark.Phalan@Sun.COM 	    reqctx->received_cert), buf, sizeof(buf));
13727934SMark.Phalan@Sun.COM 	pkiDebug("problem with cert DN = %s (error=%d) %s\n", buf, j,
13737934SMark.Phalan@Sun.COM 		 X509_verify_cert_error_string(j));
13747934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "%s\n",
13757934SMark.Phalan@Sun.COM 	    X509_verify_cert_error_string(j));
13767934SMark.Phalan@Sun.COM #ifdef DEBUG_CERTCHAIN
13777934SMark.Phalan@Sun.COM 	size = sk_X509_num(p7->d.sign->cert);
13787934SMark.Phalan@Sun.COM 	pkiDebug("received cert chain of size %d\n", size);
13797934SMark.Phalan@Sun.COM 	for (j = 0; j < size; j++) {
13807934SMark.Phalan@Sun.COM 	    X509 *tmp_cert = sk_X509_value(p7->d.sign->cert, j);
13817934SMark.Phalan@Sun.COM 	    X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, sizeof(buf));
13827934SMark.Phalan@Sun.COM 	    pkiDebug("cert #%d: %s\n", j, buf);
13837934SMark.Phalan@Sun.COM 	}
13847934SMark.Phalan@Sun.COM #endif
13857934SMark.Phalan@Sun.COM     } else {
13867934SMark.Phalan@Sun.COM 	/* retrieve verified certificate chain */
13877934SMark.Phalan@Sun.COM 	if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9)
13887934SMark.Phalan@Sun.COM 	    verified_chain = X509_STORE_CTX_get1_chain(&cert_ctx);
13897934SMark.Phalan@Sun.COM     }
13907934SMark.Phalan@Sun.COM     X509_STORE_CTX_cleanup(&cert_ctx);
13917934SMark.Phalan@Sun.COM     if (i <= 0)
13927934SMark.Phalan@Sun.COM 	goto cleanup;
13937934SMark.Phalan@Sun.COM 
13947934SMark.Phalan@Sun.COM     out = BIO_new(BIO_s_mem());
13957934SMark.Phalan@Sun.COM     if (cms_msg_type == CMS_SIGN_DRAFT9)
13967934SMark.Phalan@Sun.COM 	flags |= PKCS7_NOATTR;
13977934SMark.Phalan@Sun.COM     if (PKCS7_verify(p7, NULL, store, NULL, out, flags)) {
13987934SMark.Phalan@Sun.COM 	int valid_oid = 0;
13997934SMark.Phalan@Sun.COM 
14007934SMark.Phalan@Sun.COM 	if (!OBJ_cmp(p7->d.sign->contents->type, oid))
14017934SMark.Phalan@Sun.COM 	    valid_oid = 1;
14027934SMark.Phalan@Sun.COM 	else if (cms_msg_type == CMS_SIGN_DRAFT9) {
14037934SMark.Phalan@Sun.COM 	    /*
14047934SMark.Phalan@Sun.COM 	     * Various implementations of the pa-type 15 request use
14057934SMark.Phalan@Sun.COM 	     * different OIDS.  We check that the returned object
14067934SMark.Phalan@Sun.COM 	     * has any of the acceptable OIDs
14077934SMark.Phalan@Sun.COM 	     */
14087934SMark.Phalan@Sun.COM 	    ASN1_OBJECT *client_oid = NULL, *server_oid = NULL, *rsa_oid = NULL;
14097934SMark.Phalan@Sun.COM 	    client_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_CLIENT);
14107934SMark.Phalan@Sun.COM 	    server_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_SERVER);
14117934SMark.Phalan@Sun.COM 	    rsa_oid = pkinit_pkcs7type2oid(plgctx, CMS_ENVEL_SERVER);
14127934SMark.Phalan@Sun.COM 	    if (!OBJ_cmp(p7->d.sign->contents->type, client_oid) ||
14137934SMark.Phalan@Sun.COM 		!OBJ_cmp(p7->d.sign->contents->type, server_oid) ||
14147934SMark.Phalan@Sun.COM 		!OBJ_cmp(p7->d.sign->contents->type, rsa_oid))
14157934SMark.Phalan@Sun.COM 		valid_oid = 1;
14167934SMark.Phalan@Sun.COM 	}
14177934SMark.Phalan@Sun.COM 
14187934SMark.Phalan@Sun.COM 	if (valid_oid)
14197934SMark.Phalan@Sun.COM 	    pkiDebug("PKCS7 Verification successful\n");
14207934SMark.Phalan@Sun.COM 	else {
14217934SMark.Phalan@Sun.COM 	    pkiDebug("wrong oid in eContentType\n");
14227934SMark.Phalan@Sun.COM 	    print_buffer(p7->d.sign->contents->type->data,
14237934SMark.Phalan@Sun.COM 		(unsigned int)p7->d.sign->contents->type->length);
14247934SMark.Phalan@Sun.COM 	    retval = KRB5KDC_ERR_PREAUTH_FAILED;
14257934SMark.Phalan@Sun.COM 	    krb5_set_error_message(context, retval, "wrong oid\n");
14267934SMark.Phalan@Sun.COM 	    goto cleanup;
14277934SMark.Phalan@Sun.COM 	}
14287934SMark.Phalan@Sun.COM     }
14297934SMark.Phalan@Sun.COM     else {
14307934SMark.Phalan@Sun.COM 	unsigned long err = ERR_peek_error();
14317934SMark.Phalan@Sun.COM 	switch(ERR_GET_REASON(err)) {
14327934SMark.Phalan@Sun.COM 	    case PKCS7_R_DIGEST_FAILURE:
14337934SMark.Phalan@Sun.COM 		retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
14347934SMark.Phalan@Sun.COM 		break;
14357934SMark.Phalan@Sun.COM 	    case PKCS7_R_SIGNATURE_FAILURE:
14367934SMark.Phalan@Sun.COM 	    default:
14377934SMark.Phalan@Sun.COM 		retval = KRB5KDC_ERR_INVALID_SIG;
14387934SMark.Phalan@Sun.COM 	}
14397934SMark.Phalan@Sun.COM 	pkiDebug("PKCS7 Verification failure\n");
14407934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "%s\n",
14417934SMark.Phalan@Sun.COM 			       ERR_error_string(err, NULL));
14427934SMark.Phalan@Sun.COM 	goto cleanup;
14437934SMark.Phalan@Sun.COM     }
14447934SMark.Phalan@Sun.COM 
14457934SMark.Phalan@Sun.COM     /* transfer the data from PKCS7 message into return buffer */
14467934SMark.Phalan@Sun.COM     for (size = 0;;) {
14477934SMark.Phalan@Sun.COM 	if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
14487934SMark.Phalan@Sun.COM 	    goto cleanup;
14497934SMark.Phalan@Sun.COM 	i = BIO_read(out, &((*data)[size]), 1024 * 10);
14507934SMark.Phalan@Sun.COM 	if (i <= 0)
14517934SMark.Phalan@Sun.COM 	    break;
14527934SMark.Phalan@Sun.COM 	else
14537934SMark.Phalan@Sun.COM 	    size += i;
14547934SMark.Phalan@Sun.COM     }
14557934SMark.Phalan@Sun.COM     *data_len = size;
14567934SMark.Phalan@Sun.COM 
14577934SMark.Phalan@Sun.COM     reqctx->received_cert = X509_dup(x);
14587934SMark.Phalan@Sun.COM 
14597934SMark.Phalan@Sun.COM     /* generate authorization data */
14607934SMark.Phalan@Sun.COM     if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9) {
14617934SMark.Phalan@Sun.COM 
14627934SMark.Phalan@Sun.COM 	if (authz_data == NULL || authz_data_len == NULL)
14637934SMark.Phalan@Sun.COM 	    goto out;
14647934SMark.Phalan@Sun.COM 
14657934SMark.Phalan@Sun.COM 	*authz_data = NULL;
14667934SMark.Phalan@Sun.COM 	retval = create_identifiers_from_stack(verified_chain,
14677934SMark.Phalan@Sun.COM 					       &krb5_verified_chain);
14687934SMark.Phalan@Sun.COM 	if (retval) {
14697934SMark.Phalan@Sun.COM 	    pkiDebug("create_identifiers_from_stack failed\n");
14707934SMark.Phalan@Sun.COM 	    goto cleanup;
14717934SMark.Phalan@Sun.COM 	}
14727934SMark.Phalan@Sun.COM 
14737934SMark.Phalan@Sun.COM 	retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_verified_chain, &authz);
14747934SMark.Phalan@Sun.COM 	if (retval) {
14757934SMark.Phalan@Sun.COM 	    pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
14767934SMark.Phalan@Sun.COM 	    goto cleanup;
14777934SMark.Phalan@Sun.COM 	}
14787934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
14797934SMark.Phalan@Sun.COM 	print_buffer_bin((unsigned char *)authz->data, authz->length,
14807934SMark.Phalan@Sun.COM 			 "/tmp/kdc_ad_initial_verified_cas");
14817934SMark.Phalan@Sun.COM #endif
14827934SMark.Phalan@Sun.COM 	*authz_data = (unsigned char *)malloc(authz->length);
14837934SMark.Phalan@Sun.COM 	if (*authz_data == NULL) {
14847934SMark.Phalan@Sun.COM 	    retval = ENOMEM;
14857934SMark.Phalan@Sun.COM 	    goto cleanup;
14867934SMark.Phalan@Sun.COM 	}
14877934SMark.Phalan@Sun.COM 	(void) memcpy(*authz_data, authz->data, authz->length);
14887934SMark.Phalan@Sun.COM 	*authz_data_len = authz->length;
14897934SMark.Phalan@Sun.COM     }
14907934SMark.Phalan@Sun.COM   out:
14917934SMark.Phalan@Sun.COM     retval = 0;
14927934SMark.Phalan@Sun.COM 
14937934SMark.Phalan@Sun.COM   cleanup:
14947934SMark.Phalan@Sun.COM     if (out != NULL)
14957934SMark.Phalan@Sun.COM 	BIO_free(out);
14967934SMark.Phalan@Sun.COM     if (store != NULL)
14977934SMark.Phalan@Sun.COM 	X509_STORE_free(store);
14987934SMark.Phalan@Sun.COM     if (p7 != NULL) {
14997934SMark.Phalan@Sun.COM 	if (idctx->intermediateCAs != NULL && p7->d.sign->cert)
15007934SMark.Phalan@Sun.COM 	    sk_X509_free(intermediateCAs);
15017934SMark.Phalan@Sun.COM 	if (idctx->revoked != NULL && p7->d.sign->crl)
15027934SMark.Phalan@Sun.COM 	    sk_X509_CRL_free(revoked);
15037934SMark.Phalan@Sun.COM 	PKCS7_free(p7);
15047934SMark.Phalan@Sun.COM     }
15057934SMark.Phalan@Sun.COM     if (verified_chain != NULL)
15067934SMark.Phalan@Sun.COM 	sk_X509_pop_free(verified_chain, X509_free);
15077934SMark.Phalan@Sun.COM     if (krb5_verified_chain != NULL)
15087934SMark.Phalan@Sun.COM 	free_krb5_external_principal_identifier(&krb5_verified_chain);
15097934SMark.Phalan@Sun.COM     if (authz != NULL)
15107934SMark.Phalan@Sun.COM 	krb5_free_data(context, authz);
15117934SMark.Phalan@Sun.COM 
15127934SMark.Phalan@Sun.COM     return retval;
15137934SMark.Phalan@Sun.COM }
15147934SMark.Phalan@Sun.COM 
15157934SMark.Phalan@Sun.COM krb5_error_code
cms_envelopeddata_create(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,krb5_preauthtype pa_type,int include_certchain,unsigned char * key_pack,unsigned int key_pack_len,unsigned char ** out,unsigned int * out_len)15167934SMark.Phalan@Sun.COM cms_envelopeddata_create(krb5_context context,
15177934SMark.Phalan@Sun.COM 			 pkinit_plg_crypto_context plgctx,
15187934SMark.Phalan@Sun.COM 			 pkinit_req_crypto_context reqctx,
15197934SMark.Phalan@Sun.COM 			 pkinit_identity_crypto_context idctx,
15207934SMark.Phalan@Sun.COM 			 krb5_preauthtype pa_type,
15217934SMark.Phalan@Sun.COM 			 int include_certchain,
15227934SMark.Phalan@Sun.COM 			 unsigned char *key_pack,
15237934SMark.Phalan@Sun.COM 			 unsigned int key_pack_len,
15247934SMark.Phalan@Sun.COM 			 unsigned char **out,
15257934SMark.Phalan@Sun.COM 			 unsigned int *out_len)
15267934SMark.Phalan@Sun.COM {
15277934SMark.Phalan@Sun.COM 
15287934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
15297934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
15307934SMark.Phalan@Sun.COM     PKCS7 *p7 = NULL;
15317934SMark.Phalan@Sun.COM     BIO *in = NULL;
15327934SMark.Phalan@Sun.COM     unsigned char *p = NULL, *signed_data = NULL, *enc_data = NULL;
15337934SMark.Phalan@Sun.COM     int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY;
15347934SMark.Phalan@Sun.COM     STACK_OF(X509) *encerts = NULL;
15357934SMark.Phalan@Sun.COM     const EVP_CIPHER *cipher = NULL;
15367934SMark.Phalan@Sun.COM     int cms_msg_type;
15377934SMark.Phalan@Sun.COM 
15387934SMark.Phalan@Sun.COM     /* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */
15397934SMark.Phalan@Sun.COM     switch ((int)pa_type) {
15407934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
15417934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REP_OLD:
15427934SMark.Phalan@Sun.COM 	    cms_msg_type = CMS_SIGN_DRAFT9;
15437934SMark.Phalan@Sun.COM 	    break;
15447934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
15457934SMark.Phalan@Sun.COM 	    cms_msg_type = CMS_ENVEL_SERVER;
15467934SMark.Phalan@Sun.COM 	    break;
15477934SMark.Phalan@Sun.COM 	default:
15487934SMark.Phalan@Sun.COM 	    /* Solaris Kerberos */
15497934SMark.Phalan@Sun.COM 	    retval = EINVAL;
15507934SMark.Phalan@Sun.COM 	    goto cleanup;
15517934SMark.Phalan@Sun.COM     }
15527934SMark.Phalan@Sun.COM 
15537934SMark.Phalan@Sun.COM     retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
15547934SMark.Phalan@Sun.COM 	cms_msg_type, include_certchain, key_pack, key_pack_len,
15557934SMark.Phalan@Sun.COM 	&signed_data, (unsigned int *)&signed_data_len);
15567934SMark.Phalan@Sun.COM     if (retval) {
15577934SMark.Phalan@Sun.COM 	pkiDebug("failed to create pkcs7 signed data\n");
15587934SMark.Phalan@Sun.COM 	goto cleanup;
15597934SMark.Phalan@Sun.COM     }
15607934SMark.Phalan@Sun.COM 
15617934SMark.Phalan@Sun.COM     /* check we have client's certificate */
15627934SMark.Phalan@Sun.COM     if (reqctx->received_cert == NULL) {
15637934SMark.Phalan@Sun.COM 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
15647934SMark.Phalan@Sun.COM 	goto cleanup;
15657934SMark.Phalan@Sun.COM     }
15667934SMark.Phalan@Sun.COM     encerts = sk_X509_new_null();
15677934SMark.Phalan@Sun.COM     sk_X509_push(encerts, reqctx->received_cert);
15687934SMark.Phalan@Sun.COM 
15697934SMark.Phalan@Sun.COM     cipher = EVP_des_ede3_cbc();
15707934SMark.Phalan@Sun.COM     in = BIO_new(BIO_s_mem());
15717934SMark.Phalan@Sun.COM     switch (pa_type) {
15727934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
15737934SMark.Phalan@Sun.COM 	    prepare_enc_data(signed_data, signed_data_len, &enc_data,
15747934SMark.Phalan@Sun.COM 			     &enc_data_len);
15757934SMark.Phalan@Sun.COM 	    retval = BIO_write(in, enc_data, enc_data_len);
15767934SMark.Phalan@Sun.COM 	    if (retval != enc_data_len) {
15777934SMark.Phalan@Sun.COM 		pkiDebug("BIO_write only wrote %d\n", retval);
15787934SMark.Phalan@Sun.COM 		goto cleanup;
15797934SMark.Phalan@Sun.COM 	    }
15807934SMark.Phalan@Sun.COM 	    break;
15817934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REP_OLD:
15827934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
15837934SMark.Phalan@Sun.COM 	    retval = BIO_write(in, signed_data, signed_data_len);
15847934SMark.Phalan@Sun.COM 		if (retval != signed_data_len) {
15857934SMark.Phalan@Sun.COM 		    pkiDebug("BIO_write only wrote %d\n", retval);
15867934SMark.Phalan@Sun.COM 		    /* Solaris Kerberos */
15877934SMark.Phalan@Sun.COM 		    retval = KRB5KRB_ERR_GENERIC;
15887934SMark.Phalan@Sun.COM 		    goto cleanup;
15897934SMark.Phalan@Sun.COM 	    }
15907934SMark.Phalan@Sun.COM 	    break;
15917934SMark.Phalan@Sun.COM 	default:
15927934SMark.Phalan@Sun.COM 	    retval = -1;
15937934SMark.Phalan@Sun.COM 	    goto cleanup;
15947934SMark.Phalan@Sun.COM     }
15957934SMark.Phalan@Sun.COM 
15967934SMark.Phalan@Sun.COM     p7 = PKCS7_encrypt(encerts, in, cipher, flags);
15977934SMark.Phalan@Sun.COM     if (p7 == NULL) {
15987934SMark.Phalan@Sun.COM 	pkiDebug("failed to encrypt PKCS7 object\n");
15997934SMark.Phalan@Sun.COM 	retval = -1;
16007934SMark.Phalan@Sun.COM 	goto cleanup;
16017934SMark.Phalan@Sun.COM     }
16027934SMark.Phalan@Sun.COM     switch (pa_type) {
16037934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ:
16047934SMark.Phalan@Sun.COM 	    p7->d.enveloped->enc_data->content_type =
16057934SMark.Phalan@Sun.COM 		OBJ_nid2obj(NID_pkcs7_signed);
16067934SMark.Phalan@Sun.COM 	    break;
16077934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REP_OLD:
16087934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REQ_OLD:
16097934SMark.Phalan@Sun.COM 	    p7->d.enveloped->enc_data->content_type =
16107934SMark.Phalan@Sun.COM 		OBJ_nid2obj(NID_pkcs7_data);
16117934SMark.Phalan@Sun.COM 	    break;
16127934SMark.Phalan@Sun.COM     }
16137934SMark.Phalan@Sun.COM 
16147934SMark.Phalan@Sun.COM     *out_len = i2d_PKCS7(p7, NULL);
16157934SMark.Phalan@Sun.COM     if (!*out_len || (p = *out = (unsigned char *)malloc(*out_len)) == NULL) {
16167934SMark.Phalan@Sun.COM 	retval = ENOMEM;
16177934SMark.Phalan@Sun.COM 	goto cleanup;
16187934SMark.Phalan@Sun.COM     }
16197934SMark.Phalan@Sun.COM     retval = i2d_PKCS7(p7, &p);
16207934SMark.Phalan@Sun.COM     if (!retval) {
16217934SMark.Phalan@Sun.COM 	pkiDebug("unable to write pkcs7 object\n");
16227934SMark.Phalan@Sun.COM 	goto cleanup;
16237934SMark.Phalan@Sun.COM     }
16247934SMark.Phalan@Sun.COM     retval = 0;
16257934SMark.Phalan@Sun.COM 
16267934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
16277934SMark.Phalan@Sun.COM     print_buffer_bin(*out, *out_len, "/tmp/kdc_enveloped_data");
16287934SMark.Phalan@Sun.COM #endif
16297934SMark.Phalan@Sun.COM 
16307934SMark.Phalan@Sun.COM cleanup:
16317934SMark.Phalan@Sun.COM     if (p7 != NULL)
16327934SMark.Phalan@Sun.COM 	PKCS7_free(p7);
16337934SMark.Phalan@Sun.COM     if (in != NULL)
16347934SMark.Phalan@Sun.COM 	BIO_free(in);
16357934SMark.Phalan@Sun.COM     if (signed_data != NULL)
16367934SMark.Phalan@Sun.COM 	free(signed_data);
16377934SMark.Phalan@Sun.COM     if (enc_data != NULL)
16387934SMark.Phalan@Sun.COM 	free(enc_data);
16397934SMark.Phalan@Sun.COM     if (encerts != NULL)
16407934SMark.Phalan@Sun.COM 	sk_X509_free(encerts);
16417934SMark.Phalan@Sun.COM 
16427934SMark.Phalan@Sun.COM     return retval;
16437934SMark.Phalan@Sun.COM }
16447934SMark.Phalan@Sun.COM 
16457934SMark.Phalan@Sun.COM krb5_error_code
cms_envelopeddata_verify(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_preauthtype pa_type,int require_crl_checking,unsigned char * enveloped_data,unsigned int enveloped_data_len,unsigned char ** data,unsigned int * data_len)16467934SMark.Phalan@Sun.COM cms_envelopeddata_verify(krb5_context context,
16477934SMark.Phalan@Sun.COM 			 pkinit_plg_crypto_context plg_cryptoctx,
16487934SMark.Phalan@Sun.COM 			 pkinit_req_crypto_context req_cryptoctx,
16497934SMark.Phalan@Sun.COM 			 pkinit_identity_crypto_context id_cryptoctx,
16507934SMark.Phalan@Sun.COM 			 krb5_preauthtype pa_type,
16517934SMark.Phalan@Sun.COM 			 int require_crl_checking,
16527934SMark.Phalan@Sun.COM 			 unsigned char *enveloped_data,
16537934SMark.Phalan@Sun.COM 			 unsigned int enveloped_data_len,
16547934SMark.Phalan@Sun.COM 			 unsigned char **data,
16557934SMark.Phalan@Sun.COM 			 unsigned int *data_len)
16567934SMark.Phalan@Sun.COM {
16577934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
16587934SMark.Phalan@Sun.COM     PKCS7 *p7 = NULL;
16597934SMark.Phalan@Sun.COM     BIO *out = NULL;
16607934SMark.Phalan@Sun.COM     int i = 0;
16617934SMark.Phalan@Sun.COM     unsigned int size = 0;
16627934SMark.Phalan@Sun.COM     const unsigned char *p = enveloped_data;
16637934SMark.Phalan@Sun.COM     unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0;
16647934SMark.Phalan@Sun.COM     unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL;
16657934SMark.Phalan@Sun.COM     int msg_type = 0;
16667934SMark.Phalan@Sun.COM 
16677934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
16687934SMark.Phalan@Sun.COM     print_buffer_bin(enveloped_data, enveloped_data_len,
16697934SMark.Phalan@Sun.COM 		     "/tmp/client_envelopeddata");
16707934SMark.Phalan@Sun.COM #endif
16717934SMark.Phalan@Sun.COM     /* decode received PKCS7 message */
16727934SMark.Phalan@Sun.COM     if ((p7 = d2i_PKCS7(NULL, &p, (int)enveloped_data_len)) == NULL) {
16737934SMark.Phalan@Sun.COM 	unsigned long err = ERR_peek_error();
16747934SMark.Phalan@Sun.COM 	pkiDebug("failed to decode pkcs7\n");
16757934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "%s\n",
16767934SMark.Phalan@Sun.COM 			       ERR_error_string(err, NULL));
16777934SMark.Phalan@Sun.COM 	goto cleanup;
16787934SMark.Phalan@Sun.COM     }
16797934SMark.Phalan@Sun.COM 
16807934SMark.Phalan@Sun.COM     /* verify that the received message is PKCS7 EnvelopedData message */
16817934SMark.Phalan@Sun.COM     if (OBJ_obj2nid(p7->type) != NID_pkcs7_enveloped) {
16827934SMark.Phalan@Sun.COM 	pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n",
16837934SMark.Phalan@Sun.COM 		 OBJ_obj2nid(p7->type));
16847934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval, "wrong oid\n");
16857934SMark.Phalan@Sun.COM 	goto cleanup;
16867934SMark.Phalan@Sun.COM     }
16877934SMark.Phalan@Sun.COM 
16887934SMark.Phalan@Sun.COM     /* decrypt received PKCS7 message */
16897934SMark.Phalan@Sun.COM     out = BIO_new(BIO_s_mem());
16907934SMark.Phalan@Sun.COM     if (pkcs7_decrypt(context, id_cryptoctx, p7, out)) {
16917934SMark.Phalan@Sun.COM 	pkiDebug("PKCS7 decryption successful\n");
16927934SMark.Phalan@Sun.COM     } else {
16937934SMark.Phalan@Sun.COM 	unsigned long err = ERR_peek_error();
16947934SMark.Phalan@Sun.COM 	if (err != 0)
16957934SMark.Phalan@Sun.COM 	    krb5_set_error_message(context, retval, "%s\n",
16967934SMark.Phalan@Sun.COM 				   ERR_error_string(err, NULL));
16977934SMark.Phalan@Sun.COM 	pkiDebug("PKCS7 decryption failed\n");
16987934SMark.Phalan@Sun.COM 	goto cleanup;
16997934SMark.Phalan@Sun.COM     }
17007934SMark.Phalan@Sun.COM 
17017934SMark.Phalan@Sun.COM     /* transfer the decoded PKCS7 SignedData message into a separate buffer */
17027934SMark.Phalan@Sun.COM     for (;;) {
17037934SMark.Phalan@Sun.COM 	if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL)
17047934SMark.Phalan@Sun.COM 	    goto cleanup;
17057934SMark.Phalan@Sun.COM 	i = BIO_read(out, &(tmp_buf[size]), 1024 * 10);
17067934SMark.Phalan@Sun.COM 	if (i <= 0)
17077934SMark.Phalan@Sun.COM 	    break;
17087934SMark.Phalan@Sun.COM 	else
17097934SMark.Phalan@Sun.COM 	    size += i;
17107934SMark.Phalan@Sun.COM     }
17117934SMark.Phalan@Sun.COM     tmp_buf_len = size;
17127934SMark.Phalan@Sun.COM 
17137934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
17147934SMark.Phalan@Sun.COM     print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack");
17157934SMark.Phalan@Sun.COM #endif
17167934SMark.Phalan@Sun.COM     /* verify PKCS7 SignedData message */
17177934SMark.Phalan@Sun.COM     switch (pa_type) {
17187934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REP:
17197934SMark.Phalan@Sun.COM 	    msg_type = CMS_ENVEL_SERVER;
17207934SMark.Phalan@Sun.COM 
17217934SMark.Phalan@Sun.COM 	    break;
17227934SMark.Phalan@Sun.COM 	case KRB5_PADATA_PK_AS_REP_OLD:
17237934SMark.Phalan@Sun.COM 	    msg_type = CMS_SIGN_DRAFT9;
17247934SMark.Phalan@Sun.COM 	    break;
17257934SMark.Phalan@Sun.COM 	default:
17267934SMark.Phalan@Sun.COM 	    pkiDebug("%s: unrecognized pa_type = %d\n", __FUNCTION__, pa_type);
17277934SMark.Phalan@Sun.COM 	    retval = KRB5KDC_ERR_PREAUTH_FAILED;
17287934SMark.Phalan@Sun.COM 	    goto cleanup;
17297934SMark.Phalan@Sun.COM     }
17307934SMark.Phalan@Sun.COM     /*
17317934SMark.Phalan@Sun.COM      * If this is the RFC style, wrap the signed data to make
17327934SMark.Phalan@Sun.COM      * decoding easier in the verify routine.
17337934SMark.Phalan@Sun.COM      * For draft9-compatible, we don't do anything because it
17347934SMark.Phalan@Sun.COM      * is already wrapped.
17357934SMark.Phalan@Sun.COM      */
17367934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
17377934SMark.Phalan@Sun.COM     /*
17387934SMark.Phalan@Sun.COM      * The Longhorn server returns the expected RFC-style data, but
17397934SMark.Phalan@Sun.COM      * it is missing the sequence tag and length, so it requires
17407934SMark.Phalan@Sun.COM      * special processing when wrapping.
17417934SMark.Phalan@Sun.COM      * This will hopefully be fixed before the final release and
17427934SMark.Phalan@Sun.COM      * this can all be removed.
17437934SMark.Phalan@Sun.COM      */
17447934SMark.Phalan@Sun.COM     if (msg_type == CMS_ENVEL_SERVER || longhorn == 1) {
17457934SMark.Phalan@Sun.COM 	retval = wrap_signeddata(tmp_buf, tmp_buf_len,
17467934SMark.Phalan@Sun.COM 				 &tmp_buf2, &tmp_buf2_len, longhorn);
17477934SMark.Phalan@Sun.COM 	if (retval) {
17487934SMark.Phalan@Sun.COM 	    pkiDebug("failed to encode signeddata\n");
17497934SMark.Phalan@Sun.COM 	    goto cleanup;
17507934SMark.Phalan@Sun.COM 	}
17517934SMark.Phalan@Sun.COM 	vfy_buf = tmp_buf2;
17527934SMark.Phalan@Sun.COM 	vfy_buf_len = tmp_buf2_len;
17537934SMark.Phalan@Sun.COM 
17547934SMark.Phalan@Sun.COM     } else {
17557934SMark.Phalan@Sun.COM 	vfy_buf = tmp_buf;
17567934SMark.Phalan@Sun.COM 	vfy_buf_len = tmp_buf_len;
17577934SMark.Phalan@Sun.COM     }
17587934SMark.Phalan@Sun.COM #else
17597934SMark.Phalan@Sun.COM     if (msg_type == CMS_ENVEL_SERVER) {
17607934SMark.Phalan@Sun.COM 	retval = wrap_signeddata(tmp_buf, tmp_buf_len,
17617934SMark.Phalan@Sun.COM 				 &tmp_buf2, &tmp_buf2_len);
17627934SMark.Phalan@Sun.COM 	if (retval) {
17637934SMark.Phalan@Sun.COM 	    pkiDebug("failed to encode signeddata\n");
17647934SMark.Phalan@Sun.COM 	    goto cleanup;
17657934SMark.Phalan@Sun.COM 	}
17667934SMark.Phalan@Sun.COM 	vfy_buf = tmp_buf2;
17677934SMark.Phalan@Sun.COM 	vfy_buf_len = tmp_buf2_len;
17687934SMark.Phalan@Sun.COM 
17697934SMark.Phalan@Sun.COM     } else {
17707934SMark.Phalan@Sun.COM 	vfy_buf = tmp_buf;
17717934SMark.Phalan@Sun.COM 	vfy_buf_len = tmp_buf_len;
17727934SMark.Phalan@Sun.COM     }
17737934SMark.Phalan@Sun.COM #endif
17747934SMark.Phalan@Sun.COM 
17757934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
17767934SMark.Phalan@Sun.COM     print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2");
17777934SMark.Phalan@Sun.COM #endif
17787934SMark.Phalan@Sun.COM 
17797934SMark.Phalan@Sun.COM     retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx,
17807934SMark.Phalan@Sun.COM 				   id_cryptoctx, msg_type,
17817934SMark.Phalan@Sun.COM 				   require_crl_checking,
17827934SMark.Phalan@Sun.COM 				   vfy_buf, vfy_buf_len,
17837934SMark.Phalan@Sun.COM 				   data, data_len, NULL, NULL);
17847934SMark.Phalan@Sun.COM 
17857934SMark.Phalan@Sun.COM     if (!retval)
17867934SMark.Phalan@Sun.COM 	pkiDebug("PKCS7 Verification Success\n");
17877934SMark.Phalan@Sun.COM     else {
17887934SMark.Phalan@Sun.COM 	pkiDebug("PKCS7 Verification Failure\n");
17897934SMark.Phalan@Sun.COM 	goto cleanup;
17907934SMark.Phalan@Sun.COM     }
17917934SMark.Phalan@Sun.COM 
17927934SMark.Phalan@Sun.COM     retval = 0;
17937934SMark.Phalan@Sun.COM 
17947934SMark.Phalan@Sun.COM   cleanup:
17957934SMark.Phalan@Sun.COM 
17967934SMark.Phalan@Sun.COM     if (p7 != NULL)
17977934SMark.Phalan@Sun.COM 	PKCS7_free(p7);
17987934SMark.Phalan@Sun.COM     if (out != NULL)
17997934SMark.Phalan@Sun.COM 	BIO_free(out);
18007934SMark.Phalan@Sun.COM     if (tmp_buf != NULL)
18017934SMark.Phalan@Sun.COM 	free(tmp_buf);
18027934SMark.Phalan@Sun.COM     if (tmp_buf2 != NULL)
18037934SMark.Phalan@Sun.COM 	free(tmp_buf2);
18047934SMark.Phalan@Sun.COM 
18057934SMark.Phalan@Sun.COM     return retval;
18067934SMark.Phalan@Sun.COM }
18077934SMark.Phalan@Sun.COM 
18087934SMark.Phalan@Sun.COM /* ARGSUSED */
18097934SMark.Phalan@Sun.COM static krb5_error_code
crypto_retrieve_X509_sans(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,X509 * cert,krb5_principal ** princs_ret,krb5_principal ** upn_ret,unsigned char *** dns_ret)18107934SMark.Phalan@Sun.COM crypto_retrieve_X509_sans(krb5_context context,
18117934SMark.Phalan@Sun.COM 			  pkinit_plg_crypto_context plgctx,
18127934SMark.Phalan@Sun.COM 			  pkinit_req_crypto_context reqctx,
18137934SMark.Phalan@Sun.COM 			  X509 *cert,
18147934SMark.Phalan@Sun.COM 			  krb5_principal **princs_ret,
18157934SMark.Phalan@Sun.COM 			  krb5_principal **upn_ret,
18167934SMark.Phalan@Sun.COM 			  unsigned char ***dns_ret)
18177934SMark.Phalan@Sun.COM {
18187934SMark.Phalan@Sun.COM     krb5_error_code retval = EINVAL;
18197934SMark.Phalan@Sun.COM     char buf[DN_BUF_LEN];
18207934SMark.Phalan@Sun.COM     int p = 0, u = 0, d = 0;
18217934SMark.Phalan@Sun.COM     krb5_principal *princs = NULL;
18227934SMark.Phalan@Sun.COM     krb5_principal *upns = NULL;
18237934SMark.Phalan@Sun.COM     unsigned char **dnss = NULL;
18247934SMark.Phalan@Sun.COM     int i, num_found = 0;
18257934SMark.Phalan@Sun.COM 
18267934SMark.Phalan@Sun.COM     if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
18277934SMark.Phalan@Sun.COM 	pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
18287934SMark.Phalan@Sun.COM 	return retval;
18297934SMark.Phalan@Sun.COM     }
18307934SMark.Phalan@Sun.COM 
18317934SMark.Phalan@Sun.COM     if (cert == NULL) {
18327934SMark.Phalan@Sun.COM 	pkiDebug("%s: no certificate!\n", __FUNCTION__);
18337934SMark.Phalan@Sun.COM 	return retval;
18347934SMark.Phalan@Sun.COM     }
18357934SMark.Phalan@Sun.COM 
18367934SMark.Phalan@Sun.COM     X509_NAME_oneline(X509_get_subject_name(cert),
18377934SMark.Phalan@Sun.COM 		      buf, sizeof(buf));
18387934SMark.Phalan@Sun.COM     pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf);
18397934SMark.Phalan@Sun.COM 
18407934SMark.Phalan@Sun.COM     if ((i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) >= 0) {
18417934SMark.Phalan@Sun.COM 	X509_EXTENSION *ext = NULL;
18427934SMark.Phalan@Sun.COM 	GENERAL_NAMES *ialt = NULL;
18437934SMark.Phalan@Sun.COM 	GENERAL_NAME *gen = NULL;
18447934SMark.Phalan@Sun.COM 	int ret = 0;
18457934SMark.Phalan@Sun.COM 	unsigned int num_sans = 0;
18467934SMark.Phalan@Sun.COM 
18477934SMark.Phalan@Sun.COM 	if (!(ext = X509_get_ext(cert, i)) || !(ialt = X509V3_EXT_d2i(ext))) {
18487934SMark.Phalan@Sun.COM 	    pkiDebug("%s: found no subject alt name extensions\n",
18497934SMark.Phalan@Sun.COM 		     __FUNCTION__);
18507934SMark.Phalan@Sun.COM 	    goto cleanup;
18517934SMark.Phalan@Sun.COM 	}
18527934SMark.Phalan@Sun.COM 	num_sans = sk_GENERAL_NAME_num(ialt);
18537934SMark.Phalan@Sun.COM 
18547934SMark.Phalan@Sun.COM 	pkiDebug("%s: found %d subject alt name extension(s)\n",
18557934SMark.Phalan@Sun.COM 		 __FUNCTION__, num_sans);
18567934SMark.Phalan@Sun.COM 
18577934SMark.Phalan@Sun.COM 	/* OK, we're likely returning something. Allocate return values */
18587934SMark.Phalan@Sun.COM 	if (princs_ret != NULL) {
18597934SMark.Phalan@Sun.COM 	    princs = calloc(num_sans + 1, sizeof(krb5_principal));
18607934SMark.Phalan@Sun.COM 	    if (princs == NULL) {
18617934SMark.Phalan@Sun.COM 		retval = ENOMEM;
18627934SMark.Phalan@Sun.COM 		goto cleanup;
18637934SMark.Phalan@Sun.COM 	    }
18647934SMark.Phalan@Sun.COM 	}
18657934SMark.Phalan@Sun.COM 	if (upn_ret != NULL) {
18667934SMark.Phalan@Sun.COM 	    upns = calloc(num_sans + 1, sizeof(krb5_principal));
18677934SMark.Phalan@Sun.COM 	    if (upns == NULL) {
18687934SMark.Phalan@Sun.COM 		retval = ENOMEM;
18697934SMark.Phalan@Sun.COM 		goto cleanup;
18707934SMark.Phalan@Sun.COM 	    }
18717934SMark.Phalan@Sun.COM 	}
18727934SMark.Phalan@Sun.COM 	if (dns_ret != NULL) {
18737934SMark.Phalan@Sun.COM 	    dnss = calloc(num_sans + 1, sizeof(*dnss));
18747934SMark.Phalan@Sun.COM 	    if (dnss == NULL) {
18757934SMark.Phalan@Sun.COM 		retval = ENOMEM;
18767934SMark.Phalan@Sun.COM 		goto cleanup;
18777934SMark.Phalan@Sun.COM 	    }
18787934SMark.Phalan@Sun.COM 	}
18797934SMark.Phalan@Sun.COM 
18807934SMark.Phalan@Sun.COM 	for (i = 0; i < num_sans; i++) {
18817934SMark.Phalan@Sun.COM 	    krb5_data name = { 0, 0, NULL };
18827934SMark.Phalan@Sun.COM 
18837934SMark.Phalan@Sun.COM 	    gen = sk_GENERAL_NAME_value(ialt, i);
18847934SMark.Phalan@Sun.COM 	    switch (gen->type) {
18857934SMark.Phalan@Sun.COM 	    case GEN_OTHERNAME:
18867934SMark.Phalan@Sun.COM 		name.length = gen->d.otherName->value->value.sequence->length;
18877934SMark.Phalan@Sun.COM 		name.data = (char *)gen->d.otherName->value->value.sequence->data;
18887934SMark.Phalan@Sun.COM 		if (princs != NULL
18897934SMark.Phalan@Sun.COM 		    && OBJ_cmp(plgctx->id_pkinit_san,
18907934SMark.Phalan@Sun.COM 			       gen->d.otherName->type_id) == 0) {
18917934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
18927934SMark.Phalan@Sun.COM 		    print_buffer_bin((unsigned char *)name.data, name.length,
18937934SMark.Phalan@Sun.COM 				     "/tmp/pkinit_san");
18947934SMark.Phalan@Sun.COM #endif
18957934SMark.Phalan@Sun.COM 		    ret = k5int_decode_krb5_principal_name(&name, &princs[p]);
18967934SMark.Phalan@Sun.COM 		    if (ret) {
18977934SMark.Phalan@Sun.COM 			pkiDebug("%s: failed decoding pkinit san value\n",
18987934SMark.Phalan@Sun.COM 				 __FUNCTION__);
18997934SMark.Phalan@Sun.COM 		    } else {
19007934SMark.Phalan@Sun.COM 			p++;
19017934SMark.Phalan@Sun.COM 			num_found++;
19027934SMark.Phalan@Sun.COM 		    }
19037934SMark.Phalan@Sun.COM 		} else if (upns != NULL
19047934SMark.Phalan@Sun.COM 			   && OBJ_cmp(plgctx->id_ms_san_upn,
19057934SMark.Phalan@Sun.COM 				      gen->d.otherName->type_id) == 0) {
19067934SMark.Phalan@Sun.COM 		    ret = krb5_parse_name(context, name.data, &upns[u]);
19077934SMark.Phalan@Sun.COM 		    if (ret) {
19087934SMark.Phalan@Sun.COM 			pkiDebug("%s: failed parsing ms-upn san value\n",
19097934SMark.Phalan@Sun.COM 				 __FUNCTION__);
19107934SMark.Phalan@Sun.COM 		    } else {
19117934SMark.Phalan@Sun.COM 			u++;
19127934SMark.Phalan@Sun.COM 			num_found++;
19137934SMark.Phalan@Sun.COM 		    }
19147934SMark.Phalan@Sun.COM 		} else {
19157934SMark.Phalan@Sun.COM 		    pkiDebug("%s: unrecognized othername oid in SAN\n",
19167934SMark.Phalan@Sun.COM 			     __FUNCTION__);
19177934SMark.Phalan@Sun.COM 		    continue;
19187934SMark.Phalan@Sun.COM 		}
19197934SMark.Phalan@Sun.COM 
19207934SMark.Phalan@Sun.COM 		break;
19217934SMark.Phalan@Sun.COM 	    case GEN_DNS:
19227934SMark.Phalan@Sun.COM 		if (dnss != NULL) {
19237934SMark.Phalan@Sun.COM 		    pkiDebug("%s: found dns name = %s\n",
19247934SMark.Phalan@Sun.COM 			     __FUNCTION__, gen->d.dNSName->data);
19257934SMark.Phalan@Sun.COM 		    dnss[d] = (unsigned char *)
19267934SMark.Phalan@Sun.COM 				    strdup((char *)gen->d.dNSName->data);
19277934SMark.Phalan@Sun.COM 		    if (dnss[d] == NULL) {
19287934SMark.Phalan@Sun.COM 			pkiDebug("%s: failed to duplicate dns name\n",
19297934SMark.Phalan@Sun.COM 				 __FUNCTION__);
19307934SMark.Phalan@Sun.COM 		    } else {
19317934SMark.Phalan@Sun.COM 			d++;
19327934SMark.Phalan@Sun.COM 			num_found++;
19337934SMark.Phalan@Sun.COM 		    }
19347934SMark.Phalan@Sun.COM 		}
19357934SMark.Phalan@Sun.COM 		break;
19367934SMark.Phalan@Sun.COM 	    default:
19377934SMark.Phalan@Sun.COM 		pkiDebug("%s: SAN type = %d expecting %d\n",
19387934SMark.Phalan@Sun.COM 			 __FUNCTION__, gen->type, GEN_OTHERNAME);
19397934SMark.Phalan@Sun.COM 	    }
19407934SMark.Phalan@Sun.COM 	}
19417934SMark.Phalan@Sun.COM 	sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
19427934SMark.Phalan@Sun.COM     }
19437934SMark.Phalan@Sun.COM 
19447934SMark.Phalan@Sun.COM     retval = 0;
19457934SMark.Phalan@Sun.COM     if (princs)
19467934SMark.Phalan@Sun.COM 	*princs_ret = princs;
19477934SMark.Phalan@Sun.COM     if (upns)
19487934SMark.Phalan@Sun.COM 	*upn_ret = upns;
19497934SMark.Phalan@Sun.COM     if (dnss)
19507934SMark.Phalan@Sun.COM 	*dns_ret = dnss;
19517934SMark.Phalan@Sun.COM 
19527934SMark.Phalan@Sun.COM   cleanup:
19537934SMark.Phalan@Sun.COM     if (retval) {
19547934SMark.Phalan@Sun.COM 	if (princs != NULL) {
19557934SMark.Phalan@Sun.COM 	    for (i = 0; princs[i] != NULL; i++)
19567934SMark.Phalan@Sun.COM 		krb5_free_principal(context, princs[i]);
19577934SMark.Phalan@Sun.COM 	    free(princs);
19587934SMark.Phalan@Sun.COM 	}
19597934SMark.Phalan@Sun.COM 	if (upns != NULL) {
19607934SMark.Phalan@Sun.COM 	    for (i = 0; upns[i] != NULL; i++)
19617934SMark.Phalan@Sun.COM 		krb5_free_principal(context, upns[i]);
19627934SMark.Phalan@Sun.COM 	    free(upns);
19637934SMark.Phalan@Sun.COM 	}
19647934SMark.Phalan@Sun.COM 	if (dnss != NULL) {
19657934SMark.Phalan@Sun.COM 	    for (i = 0; dnss[i] != NULL; i++)
19667934SMark.Phalan@Sun.COM 		free(dnss[i]);
19677934SMark.Phalan@Sun.COM 	    free(dnss);
19687934SMark.Phalan@Sun.COM 	}
19697934SMark.Phalan@Sun.COM     }
19707934SMark.Phalan@Sun.COM     return retval;
19717934SMark.Phalan@Sun.COM }
19727934SMark.Phalan@Sun.COM 
19737934SMark.Phalan@Sun.COM /* ARGSUSED */
19747934SMark.Phalan@Sun.COM krb5_error_code
crypto_retrieve_cert_sans(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,krb5_principal ** princs_ret,krb5_principal ** upn_ret,unsigned char *** dns_ret)19757934SMark.Phalan@Sun.COM crypto_retrieve_cert_sans(krb5_context context,
19767934SMark.Phalan@Sun.COM 			  pkinit_plg_crypto_context plgctx,
19777934SMark.Phalan@Sun.COM 			  pkinit_req_crypto_context reqctx,
19787934SMark.Phalan@Sun.COM 			  pkinit_identity_crypto_context idctx,
19797934SMark.Phalan@Sun.COM 			  krb5_principal **princs_ret,
19807934SMark.Phalan@Sun.COM 			  krb5_principal **upn_ret,
19817934SMark.Phalan@Sun.COM 			  unsigned char ***dns_ret)
19827934SMark.Phalan@Sun.COM {
19837934SMark.Phalan@Sun.COM     krb5_error_code retval = EINVAL;
19847934SMark.Phalan@Sun.COM 
19857934SMark.Phalan@Sun.COM     if (reqctx->received_cert == NULL) {
19867934SMark.Phalan@Sun.COM 	pkiDebug("%s: No certificate!\n", __FUNCTION__);
19877934SMark.Phalan@Sun.COM 	return retval;
19887934SMark.Phalan@Sun.COM     }
19897934SMark.Phalan@Sun.COM 
19907934SMark.Phalan@Sun.COM     return crypto_retrieve_X509_sans(context, plgctx, reqctx,
19917934SMark.Phalan@Sun.COM 				     reqctx->received_cert, princs_ret,
19927934SMark.Phalan@Sun.COM 				     upn_ret, dns_ret);
19937934SMark.Phalan@Sun.COM }
19947934SMark.Phalan@Sun.COM 
19957934SMark.Phalan@Sun.COM /* ARGSUSED */
19967934SMark.Phalan@Sun.COM krb5_error_code
crypto_check_cert_eku(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,int checking_kdc_cert,int allow_secondary_usage,int * valid_eku)19977934SMark.Phalan@Sun.COM crypto_check_cert_eku(krb5_context context,
19987934SMark.Phalan@Sun.COM 		      pkinit_plg_crypto_context plgctx,
19997934SMark.Phalan@Sun.COM 		      pkinit_req_crypto_context reqctx,
20007934SMark.Phalan@Sun.COM 		      pkinit_identity_crypto_context idctx,
20017934SMark.Phalan@Sun.COM 		      int checking_kdc_cert,
20027934SMark.Phalan@Sun.COM 		      int allow_secondary_usage,
20037934SMark.Phalan@Sun.COM 		      int *valid_eku)
20047934SMark.Phalan@Sun.COM {
20057934SMark.Phalan@Sun.COM     char buf[DN_BUF_LEN];
20067934SMark.Phalan@Sun.COM     int found_eku = 0;
20077934SMark.Phalan@Sun.COM     krb5_error_code retval = EINVAL;
20087934SMark.Phalan@Sun.COM     int i;
20097934SMark.Phalan@Sun.COM 
20107934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
20117934SMark.Phalan@Sun.COM     if (valid_eku == NULL)
20127934SMark.Phalan@Sun.COM 	return retval;
20137934SMark.Phalan@Sun.COM 
20147934SMark.Phalan@Sun.COM     *valid_eku = 0;
20157934SMark.Phalan@Sun.COM     if (reqctx->received_cert == NULL)
20167934SMark.Phalan@Sun.COM 	goto cleanup;
20177934SMark.Phalan@Sun.COM 
20187934SMark.Phalan@Sun.COM     X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
20197934SMark.Phalan@Sun.COM 		      buf, sizeof(buf));
20207934SMark.Phalan@Sun.COM     pkiDebug("%s: looking for EKUs in cert = %s\n", __FUNCTION__, buf);
20217934SMark.Phalan@Sun.COM 
20227934SMark.Phalan@Sun.COM     if ((i = X509_get_ext_by_NID(reqctx->received_cert,
20237934SMark.Phalan@Sun.COM 				 NID_ext_key_usage, -1)) >= 0) {
20247934SMark.Phalan@Sun.COM 	EXTENDED_KEY_USAGE *extusage;
20257934SMark.Phalan@Sun.COM 
20267934SMark.Phalan@Sun.COM 	extusage = X509_get_ext_d2i(reqctx->received_cert, NID_ext_key_usage,
20277934SMark.Phalan@Sun.COM 				    NULL, NULL);
20287934SMark.Phalan@Sun.COM 	if (extusage) {
20297934SMark.Phalan@Sun.COM 	    pkiDebug("%s: found eku info in the cert\n", __FUNCTION__);
20307934SMark.Phalan@Sun.COM 	    for (i = 0; found_eku == 0 && i < sk_ASN1_OBJECT_num(extusage); i++) {
20317934SMark.Phalan@Sun.COM 		ASN1_OBJECT *tmp_oid;
20327934SMark.Phalan@Sun.COM 
20337934SMark.Phalan@Sun.COM 		tmp_oid = sk_ASN1_OBJECT_value(extusage, i);
20347934SMark.Phalan@Sun.COM 		pkiDebug("%s: checking eku %d of %d, allow_secondary = %d\n",
20357934SMark.Phalan@Sun.COM 			 __FUNCTION__, i+1, sk_ASN1_OBJECT_num(extusage),
20367934SMark.Phalan@Sun.COM 			 allow_secondary_usage);
20377934SMark.Phalan@Sun.COM 		if (checking_kdc_cert) {
20387934SMark.Phalan@Sun.COM 		    if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPKdc) == 0)
20397934SMark.Phalan@Sun.COM 			 || (allow_secondary_usage
20407934SMark.Phalan@Sun.COM 			 && OBJ_cmp(tmp_oid, plgctx->id_kp_serverAuth) == 0))
20417934SMark.Phalan@Sun.COM 			found_eku = 1;
20427934SMark.Phalan@Sun.COM 		} else {
20437934SMark.Phalan@Sun.COM 		    if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPClientAuth) == 0)
20447934SMark.Phalan@Sun.COM 			 || (allow_secondary_usage
20457934SMark.Phalan@Sun.COM 			 && OBJ_cmp(tmp_oid, plgctx->id_ms_kp_sc_logon) == 0))
20467934SMark.Phalan@Sun.COM 			found_eku = 1;
20477934SMark.Phalan@Sun.COM 		}
20487934SMark.Phalan@Sun.COM 	    }
20497934SMark.Phalan@Sun.COM 	}
20507934SMark.Phalan@Sun.COM 	EXTENDED_KEY_USAGE_free(extusage);
20517934SMark.Phalan@Sun.COM 
20527934SMark.Phalan@Sun.COM 	if (found_eku) {
20537934SMark.Phalan@Sun.COM 	    ASN1_BIT_STRING *usage = NULL;
20547934SMark.Phalan@Sun.COM 	    pkiDebug("%s: found acceptable EKU, checking for digitalSignature\n", __FUNCTION__);
20557934SMark.Phalan@Sun.COM 
20567934SMark.Phalan@Sun.COM 	    /* check that digitalSignature KeyUsage is present */
20577934SMark.Phalan@Sun.COM 	    if ((usage = X509_get_ext_d2i(reqctx->received_cert,
20587934SMark.Phalan@Sun.COM 					  NID_key_usage, NULL, NULL))) {
20597934SMark.Phalan@Sun.COM 
20607934SMark.Phalan@Sun.COM 		if (!ku_reject(reqctx->received_cert,
20617934SMark.Phalan@Sun.COM 			       X509v3_KU_DIGITAL_SIGNATURE)) {
20627934SMark.Phalan@Sun.COM 		    pkiDebug("%s: found digitalSignature KU\n",
20637934SMark.Phalan@Sun.COM 			     __FUNCTION__);
20647934SMark.Phalan@Sun.COM 		    *valid_eku = 1;
20657934SMark.Phalan@Sun.COM 		} else
20667934SMark.Phalan@Sun.COM 		    pkiDebug("%s: didn't find digitalSignature KU\n",
20677934SMark.Phalan@Sun.COM 			     __FUNCTION__);
20687934SMark.Phalan@Sun.COM 	    }
20697934SMark.Phalan@Sun.COM 	    ASN1_BIT_STRING_free(usage);
20707934SMark.Phalan@Sun.COM 	}
20717934SMark.Phalan@Sun.COM     }
20727934SMark.Phalan@Sun.COM     retval = 0;
20737934SMark.Phalan@Sun.COM cleanup:
20747934SMark.Phalan@Sun.COM     pkiDebug("%s: returning retval %d, valid_eku %d\n",
20757934SMark.Phalan@Sun.COM 	     __FUNCTION__, retval, *valid_eku);
20767934SMark.Phalan@Sun.COM     return retval;
20777934SMark.Phalan@Sun.COM }
20787934SMark.Phalan@Sun.COM 
20797934SMark.Phalan@Sun.COM krb5_error_code
pkinit_octetstring2key(krb5_context context,krb5_enctype etype,unsigned char * key,unsigned int dh_key_len,krb5_keyblock * key_block)20807934SMark.Phalan@Sun.COM pkinit_octetstring2key(krb5_context context,
20817934SMark.Phalan@Sun.COM 		       krb5_enctype etype,
20827934SMark.Phalan@Sun.COM 		       unsigned char *key,
20837934SMark.Phalan@Sun.COM 		       unsigned int dh_key_len,
20847934SMark.Phalan@Sun.COM 		       krb5_keyblock * key_block)
20857934SMark.Phalan@Sun.COM {
20867934SMark.Phalan@Sun.COM     krb5_error_code retval;
20877934SMark.Phalan@Sun.COM     unsigned char *buf = NULL;
20887934SMark.Phalan@Sun.COM     unsigned char md[SHA_DIGEST_LENGTH];
20897934SMark.Phalan@Sun.COM     unsigned char counter;
20907934SMark.Phalan@Sun.COM     size_t keybytes, keylength, offset;
20917934SMark.Phalan@Sun.COM     krb5_data random_data;
20927934SMark.Phalan@Sun.COM 
20937934SMark.Phalan@Sun.COM 
20947934SMark.Phalan@Sun.COM     if ((buf = (unsigned char *) malloc(dh_key_len)) == NULL) {
20957934SMark.Phalan@Sun.COM 	retval = ENOMEM;
20967934SMark.Phalan@Sun.COM 	goto cleanup;
20977934SMark.Phalan@Sun.COM     }
20987934SMark.Phalan@Sun.COM     (void) memset(buf, 0, dh_key_len);
20997934SMark.Phalan@Sun.COM 
21007934SMark.Phalan@Sun.COM     counter = 0;
21017934SMark.Phalan@Sun.COM     offset = 0;
21027934SMark.Phalan@Sun.COM     do {
21037934SMark.Phalan@Sun.COM 	SHA_CTX c;
21047934SMark.Phalan@Sun.COM 
21057934SMark.Phalan@Sun.COM 	SHA1_Init(&c);
21067934SMark.Phalan@Sun.COM 	SHA1_Update(&c, &counter, 1);
21077934SMark.Phalan@Sun.COM 	SHA1_Update(&c, key, dh_key_len);
21087934SMark.Phalan@Sun.COM 	SHA1_Final(md, &c);
21097934SMark.Phalan@Sun.COM 
21107934SMark.Phalan@Sun.COM 	if (dh_key_len - offset < sizeof(md))
21117934SMark.Phalan@Sun.COM 	    (void) memcpy(buf + offset, md, dh_key_len - offset);
21127934SMark.Phalan@Sun.COM 	else
21137934SMark.Phalan@Sun.COM 	    (void) memcpy(buf + offset, md, sizeof(md));
21147934SMark.Phalan@Sun.COM 
21157934SMark.Phalan@Sun.COM 	offset += sizeof(md);
21167934SMark.Phalan@Sun.COM 	counter++;
21177934SMark.Phalan@Sun.COM     } while (offset < dh_key_len);
21187934SMark.Phalan@Sun.COM 
21197934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
21207934SMark.Phalan@Sun.COM     key_block->magic = KV5M_KEYBLOCK;
21217934SMark.Phalan@Sun.COM     key_block->enctype = etype;
21227934SMark.Phalan@Sun.COM 
21237934SMark.Phalan@Sun.COM     retval = krb5_c_keylengths(context, etype, &keybytes, &keylength);
21247934SMark.Phalan@Sun.COM     if (retval)
21257934SMark.Phalan@Sun.COM 	goto cleanup;
21267934SMark.Phalan@Sun.COM 
21277934SMark.Phalan@Sun.COM     key_block->length = keylength;
21287934SMark.Phalan@Sun.COM     key_block->contents = calloc(keylength, sizeof(unsigned char *));
21297934SMark.Phalan@Sun.COM     if (key_block->contents == NULL) {
21307934SMark.Phalan@Sun.COM 	retval = ENOMEM;
21317934SMark.Phalan@Sun.COM 	goto cleanup;
21327934SMark.Phalan@Sun.COM     }
21337934SMark.Phalan@Sun.COM 
21347934SMark.Phalan@Sun.COM     random_data.length = keybytes;
21357934SMark.Phalan@Sun.COM     random_data.data = (char *)buf;
21367934SMark.Phalan@Sun.COM 
21377934SMark.Phalan@Sun.COM     retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
21387934SMark.Phalan@Sun.COM 
21397934SMark.Phalan@Sun.COM   cleanup:
21407934SMark.Phalan@Sun.COM     if (buf != NULL)
21417934SMark.Phalan@Sun.COM 	free(buf);
21427934SMark.Phalan@Sun.COM     if (retval && key_block->contents != NULL && key_block->length != 0) {
21437934SMark.Phalan@Sun.COM 	(void) memset(key_block->contents, 0, key_block->length);
21447934SMark.Phalan@Sun.COM 	key_block->length = 0;
21457934SMark.Phalan@Sun.COM     }
21467934SMark.Phalan@Sun.COM 
21477934SMark.Phalan@Sun.COM     return retval;
21487934SMark.Phalan@Sun.COM }
21497934SMark.Phalan@Sun.COM 
21507934SMark.Phalan@Sun.COM /* ARGSUSED */
21517934SMark.Phalan@Sun.COM krb5_error_code
client_create_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int dh_size,unsigned char ** dh_params,unsigned int * dh_params_len,unsigned char ** dh_pubkey,unsigned int * dh_pubkey_len)21527934SMark.Phalan@Sun.COM client_create_dh(krb5_context context,
21537934SMark.Phalan@Sun.COM 		 pkinit_plg_crypto_context plg_cryptoctx,
21547934SMark.Phalan@Sun.COM 		 pkinit_req_crypto_context cryptoctx,
21557934SMark.Phalan@Sun.COM 		 pkinit_identity_crypto_context id_cryptoctx,
21567934SMark.Phalan@Sun.COM 		 int dh_size,
21577934SMark.Phalan@Sun.COM 		 unsigned char **dh_params,
21587934SMark.Phalan@Sun.COM 		 unsigned int *dh_params_len,
21597934SMark.Phalan@Sun.COM 		 unsigned char **dh_pubkey,
21607934SMark.Phalan@Sun.COM 		 unsigned int *dh_pubkey_len)
21617934SMark.Phalan@Sun.COM {
21627934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
21637934SMark.Phalan@Sun.COM     unsigned char *buf = NULL;
21647934SMark.Phalan@Sun.COM     int dh_err = 0;
21657934SMark.Phalan@Sun.COM     ASN1_INTEGER *pub_key = NULL;
21667934SMark.Phalan@Sun.COM 
21677934SMark.Phalan@Sun.COM     if (cryptoctx->dh == NULL) {
21687934SMark.Phalan@Sun.COM 	if ((cryptoctx->dh = DH_new()) == NULL)
21697934SMark.Phalan@Sun.COM 	    goto cleanup;
21707934SMark.Phalan@Sun.COM 	if ((cryptoctx->dh->g = BN_new()) == NULL ||
21717934SMark.Phalan@Sun.COM 	    (cryptoctx->dh->q = BN_new()) == NULL)
21727934SMark.Phalan@Sun.COM 	    goto cleanup;
21737934SMark.Phalan@Sun.COM 
21747934SMark.Phalan@Sun.COM 	switch(dh_size) {
21757934SMark.Phalan@Sun.COM 	    case 1024:
21767934SMark.Phalan@Sun.COM 		pkiDebug("client uses 1024 DH keys\n");
21777934SMark.Phalan@Sun.COM 		cryptoctx->dh->p = get_rfc2409_prime_1024(NULL);
21787934SMark.Phalan@Sun.COM 		break;
21797934SMark.Phalan@Sun.COM 	    case 2048:
21807934SMark.Phalan@Sun.COM 		pkiDebug("client uses 2048 DH keys\n");
21817934SMark.Phalan@Sun.COM 		cryptoctx->dh->p = BN_bin2bn(pkinit_2048_dhprime,
21827934SMark.Phalan@Sun.COM 		    sizeof(pkinit_2048_dhprime), NULL);
21837934SMark.Phalan@Sun.COM 		break;
21847934SMark.Phalan@Sun.COM 	    case 4096:
21857934SMark.Phalan@Sun.COM 		pkiDebug("client uses 4096 DH keys\n");
21867934SMark.Phalan@Sun.COM 		cryptoctx->dh->p = BN_bin2bn(pkinit_4096_dhprime,
21877934SMark.Phalan@Sun.COM 		    sizeof(pkinit_4096_dhprime), NULL);
21887934SMark.Phalan@Sun.COM 		break;
21897934SMark.Phalan@Sun.COM 	    default:
21907934SMark.Phalan@Sun.COM 		goto cleanup;
21917934SMark.Phalan@Sun.COM 	}
21927934SMark.Phalan@Sun.COM 
21937934SMark.Phalan@Sun.COM 	BN_set_word((cryptoctx->dh->g), DH_GENERATOR_2);
21947934SMark.Phalan@Sun.COM 	BN_rshift1(cryptoctx->dh->q, cryptoctx->dh->p);
21957934SMark.Phalan@Sun.COM     }
21967934SMark.Phalan@Sun.COM 
21977934SMark.Phalan@Sun.COM     DH_generate_key(cryptoctx->dh);
21987934SMark.Phalan@Sun.COM /* Solaris Kerberos */
21997934SMark.Phalan@Sun.COM #ifdef DEBUG
22007934SMark.Phalan@Sun.COM     DH_check(cryptoctx->dh, &dh_err);
22017934SMark.Phalan@Sun.COM     if (dh_err != 0) {
22027934SMark.Phalan@Sun.COM 	pkiDebug("Warning: dh_check failed with %d\n", dh_err);
22037934SMark.Phalan@Sun.COM 	if (dh_err & DH_CHECK_P_NOT_PRIME)
22047934SMark.Phalan@Sun.COM 	    pkiDebug("p value is not prime\n");
22057934SMark.Phalan@Sun.COM 	if (dh_err & DH_CHECK_P_NOT_SAFE_PRIME)
22067934SMark.Phalan@Sun.COM 	    pkiDebug("p value is not a safe prime\n");
22077934SMark.Phalan@Sun.COM 	if (dh_err & DH_UNABLE_TO_CHECK_GENERATOR)
22087934SMark.Phalan@Sun.COM 	    pkiDebug("unable to check the generator value\n");
22097934SMark.Phalan@Sun.COM 	if (dh_err & DH_NOT_SUITABLE_GENERATOR)
22107934SMark.Phalan@Sun.COM 	    pkiDebug("the g value is not a generator\n");
22117934SMark.Phalan@Sun.COM     }
22127934SMark.Phalan@Sun.COM #endif
22137934SMark.Phalan@Sun.COM #ifdef DEBUG_DH
22147934SMark.Phalan@Sun.COM     print_dh(cryptoctx->dh, "client's DH params\n");
22157934SMark.Phalan@Sun.COM     print_pubkey(cryptoctx->dh->pub_key, "client's pub_key=");
22167934SMark.Phalan@Sun.COM #endif
22177934SMark.Phalan@Sun.COM 
22187934SMark.Phalan@Sun.COM     DH_check_pub_key(cryptoctx->dh, cryptoctx->dh->pub_key, &dh_err);
22197934SMark.Phalan@Sun.COM     if (dh_err != 0) {
22207934SMark.Phalan@Sun.COM 	pkiDebug("dh_check_pub_key failed with %d\n", dh_err);
22217934SMark.Phalan@Sun.COM 	goto cleanup;
22227934SMark.Phalan@Sun.COM     }
22237934SMark.Phalan@Sun.COM 
22247934SMark.Phalan@Sun.COM     /* pack DHparams */
22257934SMark.Phalan@Sun.COM     /* aglo: usually we could just call i2d_DHparams to encode DH params
22267934SMark.Phalan@Sun.COM      * however, PKINIT requires RFC3279 encoding and openssl does pkcs#3.
22277934SMark.Phalan@Sun.COM      */
22287934SMark.Phalan@Sun.COM     retval = pkinit_encode_dh_params(cryptoctx->dh->p, cryptoctx->dh->g,
22297934SMark.Phalan@Sun.COM 	cryptoctx->dh->q, dh_params, dh_params_len);
22307934SMark.Phalan@Sun.COM     if (retval)
22317934SMark.Phalan@Sun.COM 	goto cleanup;
22327934SMark.Phalan@Sun.COM 
22337934SMark.Phalan@Sun.COM     /* pack DH public key */
22347934SMark.Phalan@Sun.COM     /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
22357934SMark.Phalan@Sun.COM      * encoding shall be used as the contents (the value) of the
22367934SMark.Phalan@Sun.COM      * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
22377934SMark.Phalan@Sun.COM      * data element
22387934SMark.Phalan@Sun.COM      */
22397934SMark.Phalan@Sun.COM     if ((pub_key = BN_to_ASN1_INTEGER(cryptoctx->dh->pub_key, NULL)) == NULL)
22407934SMark.Phalan@Sun.COM 	goto cleanup;
22417934SMark.Phalan@Sun.COM     *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
22427934SMark.Phalan@Sun.COM     if ((buf = *dh_pubkey = (unsigned char *)
22437934SMark.Phalan@Sun.COM 	    malloc((size_t) *dh_pubkey_len)) == NULL) {
22447934SMark.Phalan@Sun.COM 	retval  = ENOMEM;
22457934SMark.Phalan@Sun.COM 	goto cleanup;
22467934SMark.Phalan@Sun.COM     }
22477934SMark.Phalan@Sun.COM     i2d_ASN1_INTEGER(pub_key, &buf);
22487934SMark.Phalan@Sun.COM 
22497934SMark.Phalan@Sun.COM     if (pub_key != NULL)
22507934SMark.Phalan@Sun.COM 	ASN1_INTEGER_free(pub_key);
22517934SMark.Phalan@Sun.COM 
22527934SMark.Phalan@Sun.COM     retval = 0;
22537934SMark.Phalan@Sun.COM     return retval;
22547934SMark.Phalan@Sun.COM 
22557934SMark.Phalan@Sun.COM   cleanup:
22567934SMark.Phalan@Sun.COM     if (cryptoctx->dh != NULL)
22577934SMark.Phalan@Sun.COM 	DH_free(cryptoctx->dh);
22587934SMark.Phalan@Sun.COM     cryptoctx->dh = NULL;
22597934SMark.Phalan@Sun.COM     if (*dh_params != NULL)
22607934SMark.Phalan@Sun.COM 	free(*dh_params);
22617934SMark.Phalan@Sun.COM     *dh_params = NULL;
22627934SMark.Phalan@Sun.COM     if (*dh_pubkey != NULL)
22637934SMark.Phalan@Sun.COM 	free(*dh_pubkey);
22647934SMark.Phalan@Sun.COM     *dh_pubkey = NULL;
22657934SMark.Phalan@Sun.COM     if (pub_key != NULL)
22667934SMark.Phalan@Sun.COM 	ASN1_INTEGER_free(pub_key);
22677934SMark.Phalan@Sun.COM 
22687934SMark.Phalan@Sun.COM     return retval;
22697934SMark.Phalan@Sun.COM }
22707934SMark.Phalan@Sun.COM 
22717934SMark.Phalan@Sun.COM /* ARGSUSED */
22727934SMark.Phalan@Sun.COM krb5_error_code
client_process_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char * subjectPublicKey_data,unsigned int subjectPublicKey_length,unsigned char ** client_key,unsigned int * client_key_len)22737934SMark.Phalan@Sun.COM client_process_dh(krb5_context context,
22747934SMark.Phalan@Sun.COM 		  pkinit_plg_crypto_context plg_cryptoctx,
22757934SMark.Phalan@Sun.COM 		  pkinit_req_crypto_context cryptoctx,
22767934SMark.Phalan@Sun.COM 		  pkinit_identity_crypto_context id_cryptoctx,
22777934SMark.Phalan@Sun.COM 		  unsigned char *subjectPublicKey_data,
22787934SMark.Phalan@Sun.COM 		  unsigned int subjectPublicKey_length,
22797934SMark.Phalan@Sun.COM 		  unsigned char **client_key,
22807934SMark.Phalan@Sun.COM 		  unsigned int *client_key_len)
22817934SMark.Phalan@Sun.COM {
22827934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
22837934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5_PREAUTH_FAILED;
22847934SMark.Phalan@Sun.COM     BIGNUM *server_pub_key = NULL;
22857934SMark.Phalan@Sun.COM     ASN1_INTEGER *pub_key = NULL;
22867934SMark.Phalan@Sun.COM     const unsigned char *p = NULL;
22877934SMark.Phalan@Sun.COM     unsigned char *data = NULL;
22887934SMark.Phalan@Sun.COM     long data_len;
22897934SMark.Phalan@Sun.COM 
22907934SMark.Phalan@Sun.COM     /* decode subjectPublicKey (retrieve INTEGER from OCTET_STRING) */
22917934SMark.Phalan@Sun.COM 
22927934SMark.Phalan@Sun.COM     if (der_decode_data(subjectPublicKey_data, (long)subjectPublicKey_length,
22937934SMark.Phalan@Sun.COM 			&data, &data_len) != 0) {
22947934SMark.Phalan@Sun.COM 	pkiDebug("failed to decode subjectPublicKey\n");
22957934SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
22967934SMark.Phalan@Sun.COM 	retval = KRB5_PREAUTH_FAILED;
22977934SMark.Phalan@Sun.COM 	goto cleanup;
22987934SMark.Phalan@Sun.COM     }
22997934SMark.Phalan@Sun.COM 
23007934SMark.Phalan@Sun.COM     *client_key_len = DH_size(cryptoctx->dh);
23017934SMark.Phalan@Sun.COM     if ((*client_key = (unsigned char *)
23027934SMark.Phalan@Sun.COM 	    malloc((size_t) *client_key_len)) == NULL) {
23037934SMark.Phalan@Sun.COM 	retval = ENOMEM;
23047934SMark.Phalan@Sun.COM 	goto cleanup;
23057934SMark.Phalan@Sun.COM     }
23067934SMark.Phalan@Sun.COM     p = data;
23077934SMark.Phalan@Sun.COM     if ((pub_key = d2i_ASN1_INTEGER(NULL, &p, data_len)) == NULL)
23087934SMark.Phalan@Sun.COM 	goto cleanup;
23097934SMark.Phalan@Sun.COM     if ((server_pub_key = ASN1_INTEGER_to_BN(pub_key, NULL)) == NULL)
23107934SMark.Phalan@Sun.COM 	goto cleanup;
23117934SMark.Phalan@Sun.COM 
23127934SMark.Phalan@Sun.COM     DH_compute_key(*client_key, server_pub_key, cryptoctx->dh);
23137934SMark.Phalan@Sun.COM #ifdef DEBUG_DH
23147934SMark.Phalan@Sun.COM     print_pubkey(server_pub_key, "server's pub_key=");
23157934SMark.Phalan@Sun.COM     pkiDebug("client secret key (%d)= ", *client_key_len);
23167934SMark.Phalan@Sun.COM     print_buffer(*client_key, *client_key_len);
23177934SMark.Phalan@Sun.COM #endif
23187934SMark.Phalan@Sun.COM 
23197934SMark.Phalan@Sun.COM     retval = 0;
23207934SMark.Phalan@Sun.COM     if (server_pub_key != NULL)
23217934SMark.Phalan@Sun.COM 	BN_free(server_pub_key);
23227934SMark.Phalan@Sun.COM     if (pub_key != NULL)
23237934SMark.Phalan@Sun.COM 	ASN1_INTEGER_free(pub_key);
23247934SMark.Phalan@Sun.COM     if (data != NULL)
23257934SMark.Phalan@Sun.COM 	free (data);
23267934SMark.Phalan@Sun.COM 
23277934SMark.Phalan@Sun.COM     return retval;
23287934SMark.Phalan@Sun.COM 
23297934SMark.Phalan@Sun.COM   cleanup:
23307934SMark.Phalan@Sun.COM     if (*client_key != NULL)
23317934SMark.Phalan@Sun.COM 	free(*client_key);
23327934SMark.Phalan@Sun.COM     *client_key = NULL;
23337934SMark.Phalan@Sun.COM     if (pub_key != NULL)
23347934SMark.Phalan@Sun.COM 	ASN1_INTEGER_free(pub_key);
23357934SMark.Phalan@Sun.COM     if (data != NULL)
23367934SMark.Phalan@Sun.COM 	free (data);
23377934SMark.Phalan@Sun.COM 
23387934SMark.Phalan@Sun.COM     return retval;
23397934SMark.Phalan@Sun.COM }
23407934SMark.Phalan@Sun.COM 
23417934SMark.Phalan@Sun.COM /* ARGSUSED */
23427934SMark.Phalan@Sun.COM krb5_error_code
server_check_dh(krb5_context context,pkinit_plg_crypto_context cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_octet_data * dh_params,int minbits)23437934SMark.Phalan@Sun.COM server_check_dh(krb5_context context,
23447934SMark.Phalan@Sun.COM 		pkinit_plg_crypto_context cryptoctx,
23457934SMark.Phalan@Sun.COM 		pkinit_req_crypto_context req_cryptoctx,
23467934SMark.Phalan@Sun.COM 		pkinit_identity_crypto_context id_cryptoctx,
23477934SMark.Phalan@Sun.COM 		krb5_octet_data *dh_params,
23487934SMark.Phalan@Sun.COM 		int minbits)
23497934SMark.Phalan@Sun.COM {
23507934SMark.Phalan@Sun.COM     DH *dh = NULL;
23517934SMark.Phalan@Sun.COM     unsigned char *tmp = NULL;
23527934SMark.Phalan@Sun.COM     int dh_prime_bits;
23537934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
23547934SMark.Phalan@Sun.COM 
23557934SMark.Phalan@Sun.COM     tmp = dh_params->data;
23567934SMark.Phalan@Sun.COM     dh = DH_new();
23577934SMark.Phalan@Sun.COM     dh = pkinit_decode_dh_params(&dh, &tmp, dh_params->length);
23587934SMark.Phalan@Sun.COM     if (dh == NULL) {
23597934SMark.Phalan@Sun.COM 	pkiDebug("failed to decode dhparams\n");
23607934SMark.Phalan@Sun.COM 	goto cleanup;
23617934SMark.Phalan@Sun.COM     }
23627934SMark.Phalan@Sun.COM 
23637934SMark.Phalan@Sun.COM     /* KDC SHOULD check to see if the key parameters satisfy its policy */
23647934SMark.Phalan@Sun.COM     dh_prime_bits = BN_num_bits(dh->p);
23657934SMark.Phalan@Sun.COM     if (minbits && dh_prime_bits < minbits) {
23667934SMark.Phalan@Sun.COM 	pkiDebug("client sent dh params with %d bits, we require %d\n",
23677934SMark.Phalan@Sun.COM 		 dh_prime_bits, minbits);
23687934SMark.Phalan@Sun.COM 	goto cleanup;
23697934SMark.Phalan@Sun.COM     }
23707934SMark.Phalan@Sun.COM 
23717934SMark.Phalan@Sun.COM     /* check dhparams is group 2 */
23727934SMark.Phalan@Sun.COM     if (pkinit_check_dh_params(cryptoctx->dh_1024->p,
23737934SMark.Phalan@Sun.COM 			       dh->p, dh->g, dh->q) == 0) {
23747934SMark.Phalan@Sun.COM 	retval = 0;
23757934SMark.Phalan@Sun.COM 	goto cleanup;
23767934SMark.Phalan@Sun.COM     }
23777934SMark.Phalan@Sun.COM 
23787934SMark.Phalan@Sun.COM     /* check dhparams is group 14 */
23797934SMark.Phalan@Sun.COM     if (pkinit_check_dh_params(cryptoctx->dh_2048->p,
23807934SMark.Phalan@Sun.COM 			       dh->p, dh->g, dh->q) == 0) {
23817934SMark.Phalan@Sun.COM 	retval = 0;
23827934SMark.Phalan@Sun.COM 	goto cleanup;
23837934SMark.Phalan@Sun.COM     }
23847934SMark.Phalan@Sun.COM 
23857934SMark.Phalan@Sun.COM     /* check dhparams is group 16 */
23867934SMark.Phalan@Sun.COM     if (pkinit_check_dh_params(cryptoctx->dh_4096->p,
23877934SMark.Phalan@Sun.COM 			       dh->p, dh->g, dh->q) == 0) {
23887934SMark.Phalan@Sun.COM 	retval = 0;
23897934SMark.Phalan@Sun.COM 	goto cleanup;
23907934SMark.Phalan@Sun.COM     }
23917934SMark.Phalan@Sun.COM 
23927934SMark.Phalan@Sun.COM   cleanup:
23937934SMark.Phalan@Sun.COM     if (retval == 0)
23947934SMark.Phalan@Sun.COM 	req_cryptoctx->dh = dh;
23957934SMark.Phalan@Sun.COM     else
23967934SMark.Phalan@Sun.COM 	DH_free(dh);
23977934SMark.Phalan@Sun.COM 
23987934SMark.Phalan@Sun.COM     return retval;
23997934SMark.Phalan@Sun.COM }
24007934SMark.Phalan@Sun.COM 
24017934SMark.Phalan@Sun.COM /* kdc's dh function */
24027934SMark.Phalan@Sun.COM /* ARGSUSED */
24037934SMark.Phalan@Sun.COM krb5_error_code
server_process_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** dh_pubkey,unsigned int * dh_pubkey_len,unsigned char ** server_key,unsigned int * server_key_len)24047934SMark.Phalan@Sun.COM server_process_dh(krb5_context context,
24057934SMark.Phalan@Sun.COM 		  pkinit_plg_crypto_context plg_cryptoctx,
24067934SMark.Phalan@Sun.COM 		  pkinit_req_crypto_context cryptoctx,
24077934SMark.Phalan@Sun.COM 		  pkinit_identity_crypto_context id_cryptoctx,
24087934SMark.Phalan@Sun.COM 		  unsigned char *data,
24097934SMark.Phalan@Sun.COM 		  unsigned int data_len,
24107934SMark.Phalan@Sun.COM 		  unsigned char **dh_pubkey,
24117934SMark.Phalan@Sun.COM 		  unsigned int *dh_pubkey_len,
24127934SMark.Phalan@Sun.COM 		  unsigned char **server_key,
24137934SMark.Phalan@Sun.COM 		  unsigned int *server_key_len)
24147934SMark.Phalan@Sun.COM {
24157934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
24167934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
24177934SMark.Phalan@Sun.COM     DH *dh = NULL, *dh_server = NULL;
24187934SMark.Phalan@Sun.COM     unsigned char *p = NULL;
24197934SMark.Phalan@Sun.COM     ASN1_INTEGER *pub_key = NULL;
24207934SMark.Phalan@Sun.COM 
24217934SMark.Phalan@Sun.COM     /* get client's received DH parameters that we saved in server_check_dh */
24227934SMark.Phalan@Sun.COM     dh = cryptoctx->dh;
24237934SMark.Phalan@Sun.COM 
24247934SMark.Phalan@Sun.COM     dh_server = DH_new();
24257934SMark.Phalan@Sun.COM     if (dh_server == NULL)
24267934SMark.Phalan@Sun.COM 	goto cleanup;
24277934SMark.Phalan@Sun.COM     dh_server->p = BN_dup(dh->p);
24287934SMark.Phalan@Sun.COM     dh_server->g = BN_dup(dh->g);
24297934SMark.Phalan@Sun.COM     dh_server->q = BN_dup(dh->q);
24307934SMark.Phalan@Sun.COM 
24317934SMark.Phalan@Sun.COM     /* decode client's public key */
24327934SMark.Phalan@Sun.COM     p = data;
24337934SMark.Phalan@Sun.COM     pub_key = d2i_ASN1_INTEGER(NULL, (const unsigned char **)&p, (int)data_len);
24347934SMark.Phalan@Sun.COM     if (pub_key == NULL)
24357934SMark.Phalan@Sun.COM 	goto cleanup;
24367934SMark.Phalan@Sun.COM     dh->pub_key = ASN1_INTEGER_to_BN(pub_key, NULL);
24377934SMark.Phalan@Sun.COM     if (dh->pub_key == NULL)
24387934SMark.Phalan@Sun.COM 	goto cleanup;
24397934SMark.Phalan@Sun.COM     ASN1_INTEGER_free(pub_key);
24407934SMark.Phalan@Sun.COM 
24417934SMark.Phalan@Sun.COM     if (!DH_generate_key(dh_server))
24427934SMark.Phalan@Sun.COM 	goto cleanup;
24437934SMark.Phalan@Sun.COM 
24447934SMark.Phalan@Sun.COM     /* generate DH session key */
24457934SMark.Phalan@Sun.COM     *server_key_len = DH_size(dh_server);
24467934SMark.Phalan@Sun.COM     if ((*server_key = (unsigned char *) malloc((size_t)*server_key_len)) == NULL)
24477934SMark.Phalan@Sun.COM 	goto cleanup;
24487934SMark.Phalan@Sun.COM     DH_compute_key(*server_key, dh->pub_key, dh_server);
24497934SMark.Phalan@Sun.COM 
24507934SMark.Phalan@Sun.COM #ifdef DEBUG_DH
24517934SMark.Phalan@Sun.COM     print_dh(dh_server, "client&server's DH params\n");
24527934SMark.Phalan@Sun.COM     print_pubkey(dh->pub_key, "client's pub_key=");
24537934SMark.Phalan@Sun.COM     print_pubkey(dh_server->pub_key, "server's pub_key=");
24547934SMark.Phalan@Sun.COM     pkiDebug("server secret key=");
24557934SMark.Phalan@Sun.COM     print_buffer(*server_key, *server_key_len);
24567934SMark.Phalan@Sun.COM #endif
24577934SMark.Phalan@Sun.COM 
24587934SMark.Phalan@Sun.COM     /* KDC reply */
24597934SMark.Phalan@Sun.COM     /* pack DH public key */
24607934SMark.Phalan@Sun.COM     /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
24617934SMark.Phalan@Sun.COM      * encoding shall be used as the contents (the value) of the
24627934SMark.Phalan@Sun.COM      * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
24637934SMark.Phalan@Sun.COM      * data element
24647934SMark.Phalan@Sun.COM      */
24657934SMark.Phalan@Sun.COM     if ((pub_key = BN_to_ASN1_INTEGER(dh_server->pub_key, NULL)) == NULL)
24667934SMark.Phalan@Sun.COM 	goto cleanup;
24677934SMark.Phalan@Sun.COM     *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
24687934SMark.Phalan@Sun.COM     if ((p = *dh_pubkey = (unsigned char *) malloc((size_t)*dh_pubkey_len)) == NULL)
24697934SMark.Phalan@Sun.COM 	goto cleanup;
24707934SMark.Phalan@Sun.COM     i2d_ASN1_INTEGER(pub_key, &p);
24717934SMark.Phalan@Sun.COM     if (pub_key != NULL)
24727934SMark.Phalan@Sun.COM 	ASN1_INTEGER_free(pub_key);
24737934SMark.Phalan@Sun.COM 
24747934SMark.Phalan@Sun.COM     retval = 0;
24757934SMark.Phalan@Sun.COM 
24767934SMark.Phalan@Sun.COM     if (dh_server != NULL)
24777934SMark.Phalan@Sun.COM 	DH_free(dh_server);
24787934SMark.Phalan@Sun.COM     return retval;
24797934SMark.Phalan@Sun.COM 
24807934SMark.Phalan@Sun.COM   cleanup:
24817934SMark.Phalan@Sun.COM     if (dh_server != NULL)
24827934SMark.Phalan@Sun.COM 	DH_free(dh_server);
24837934SMark.Phalan@Sun.COM     if (*dh_pubkey != NULL)
24847934SMark.Phalan@Sun.COM 	free(*dh_pubkey);
24857934SMark.Phalan@Sun.COM     if (*server_key != NULL)
24867934SMark.Phalan@Sun.COM 	free(*server_key);
24877934SMark.Phalan@Sun.COM 
24887934SMark.Phalan@Sun.COM     return retval;
24897934SMark.Phalan@Sun.COM }
24907934SMark.Phalan@Sun.COM 
249112359SMark.Phalan@Sun.COM /*
249212359SMark.Phalan@Sun.COM  * Solaris Kerberos:
249312359SMark.Phalan@Sun.COM  * Add locking around did_init to make it MT-safe.
249412359SMark.Phalan@Sun.COM  */
249512359SMark.Phalan@Sun.COM static krb5_error_code
openssl_init()24967934SMark.Phalan@Sun.COM openssl_init()
24977934SMark.Phalan@Sun.COM {
249812359SMark.Phalan@Sun.COM     krb5_error_code ret = 0;
24997934SMark.Phalan@Sun.COM     static int did_init = 0;
250012359SMark.Phalan@Sun.COM     static k5_mutex_t init_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
250112359SMark.Phalan@Sun.COM 
250212359SMark.Phalan@Sun.COM     ret = k5_mutex_lock(&init_mutex);
250312359SMark.Phalan@Sun.COM     if (ret == 0) {
250412359SMark.Phalan@Sun.COM 	if (!did_init) {
250512359SMark.Phalan@Sun.COM 	    /* initialize openssl routines */
250612359SMark.Phalan@Sun.COM 	    CRYPTO_malloc_init();
250712359SMark.Phalan@Sun.COM 	    ERR_load_crypto_strings();
250812359SMark.Phalan@Sun.COM 	    OpenSSL_add_all_algorithms();
250912359SMark.Phalan@Sun.COM 	    did_init++;
251012359SMark.Phalan@Sun.COM 	}
251112359SMark.Phalan@Sun.COM 	k5_mutex_unlock(&init_mutex);
251212359SMark.Phalan@Sun.COM     }
251312359SMark.Phalan@Sun.COM     return (ret);
25147934SMark.Phalan@Sun.COM }
25157934SMark.Phalan@Sun.COM 
25167934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_encode_dh_params(BIGNUM * p,BIGNUM * g,BIGNUM * q,unsigned char ** buf,unsigned int * buf_len)25177934SMark.Phalan@Sun.COM pkinit_encode_dh_params(BIGNUM *p, BIGNUM *g, BIGNUM *q,
25187934SMark.Phalan@Sun.COM 			unsigned char **buf, unsigned int *buf_len)
25197934SMark.Phalan@Sun.COM {
25207934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
25217934SMark.Phalan@Sun.COM     int bufsize = 0, r = 0;
25227934SMark.Phalan@Sun.COM     unsigned char *tmp = NULL;
25237934SMark.Phalan@Sun.COM     ASN1_INTEGER *ap = NULL, *ag = NULL, *aq = NULL;
25247934SMark.Phalan@Sun.COM 
25257934SMark.Phalan@Sun.COM     if ((ap = BN_to_ASN1_INTEGER(p, NULL)) == NULL)
25267934SMark.Phalan@Sun.COM 	goto cleanup;
25277934SMark.Phalan@Sun.COM     if ((ag = BN_to_ASN1_INTEGER(g, NULL)) == NULL)
25287934SMark.Phalan@Sun.COM 	goto cleanup;
25297934SMark.Phalan@Sun.COM     if ((aq = BN_to_ASN1_INTEGER(q, NULL)) == NULL)
25307934SMark.Phalan@Sun.COM 	goto cleanup;
25317934SMark.Phalan@Sun.COM     bufsize = i2d_ASN1_INTEGER(ap, NULL);
25327934SMark.Phalan@Sun.COM     bufsize += i2d_ASN1_INTEGER(ag, NULL);
25337934SMark.Phalan@Sun.COM     bufsize += i2d_ASN1_INTEGER(aq, NULL);
25347934SMark.Phalan@Sun.COM 
25357934SMark.Phalan@Sun.COM     r = ASN1_object_size(1, bufsize, V_ASN1_SEQUENCE);
25367934SMark.Phalan@Sun.COM 
25377934SMark.Phalan@Sun.COM     tmp = *buf = (unsigned char *)malloc((size_t) r);
25387934SMark.Phalan@Sun.COM     if (tmp == NULL)
25397934SMark.Phalan@Sun.COM 	goto cleanup;
25407934SMark.Phalan@Sun.COM 
25417934SMark.Phalan@Sun.COM     ASN1_put_object(&tmp, 1, bufsize, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
25427934SMark.Phalan@Sun.COM 
25437934SMark.Phalan@Sun.COM     i2d_ASN1_INTEGER(ap, &tmp);
25447934SMark.Phalan@Sun.COM     i2d_ASN1_INTEGER(ag, &tmp);
25457934SMark.Phalan@Sun.COM     i2d_ASN1_INTEGER(aq, &tmp);
25467934SMark.Phalan@Sun.COM 
25477934SMark.Phalan@Sun.COM     *buf_len = r;
25487934SMark.Phalan@Sun.COM 
25497934SMark.Phalan@Sun.COM     retval = 0;
25507934SMark.Phalan@Sun.COM 
25517934SMark.Phalan@Sun.COM cleanup:
25527934SMark.Phalan@Sun.COM     if (ap != NULL)
25537934SMark.Phalan@Sun.COM 	ASN1_INTEGER_free(ap);
25547934SMark.Phalan@Sun.COM     if (ag != NULL)
25557934SMark.Phalan@Sun.COM 	ASN1_INTEGER_free(ag);
25567934SMark.Phalan@Sun.COM     if (aq != NULL)
25577934SMark.Phalan@Sun.COM 	ASN1_INTEGER_free(aq);
25587934SMark.Phalan@Sun.COM 
25597934SMark.Phalan@Sun.COM     return retval;
25607934SMark.Phalan@Sun.COM }
25617934SMark.Phalan@Sun.COM 
25627934SMark.Phalan@Sun.COM static DH *
pkinit_decode_dh_params(DH ** a,unsigned char ** pp,unsigned int len)25637934SMark.Phalan@Sun.COM pkinit_decode_dh_params(DH ** a, unsigned char **pp, unsigned int len)
25647934SMark.Phalan@Sun.COM {
25657934SMark.Phalan@Sun.COM     ASN1_INTEGER ai, *aip = NULL;
25667934SMark.Phalan@Sun.COM     long length = (long) len;
25677934SMark.Phalan@Sun.COM 
25687934SMark.Phalan@Sun.COM     M_ASN1_D2I_vars(a, DH *, DH_new);
25697934SMark.Phalan@Sun.COM 
25707934SMark.Phalan@Sun.COM     M_ASN1_D2I_Init();
25717934SMark.Phalan@Sun.COM     M_ASN1_D2I_start_sequence();
25727934SMark.Phalan@Sun.COM     aip = &ai;
25737934SMark.Phalan@Sun.COM     ai.data = NULL;
25747934SMark.Phalan@Sun.COM     ai.length = 0;
25757934SMark.Phalan@Sun.COM     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
25767934SMark.Phalan@Sun.COM     if (aip == NULL)
25777934SMark.Phalan@Sun.COM 	return NULL;
25787934SMark.Phalan@Sun.COM     else {
25797934SMark.Phalan@Sun.COM 	(*a)->p = ASN1_INTEGER_to_BN(aip, NULL);
25807934SMark.Phalan@Sun.COM 	if ((*a)->p == NULL)
25817934SMark.Phalan@Sun.COM 	    return NULL;
25827934SMark.Phalan@Sun.COM 	if (ai.data != NULL) {
25837934SMark.Phalan@Sun.COM 	    OPENSSL_free(ai.data);
25847934SMark.Phalan@Sun.COM 	    ai.data = NULL;
25857934SMark.Phalan@Sun.COM 	    ai.length = 0;
25867934SMark.Phalan@Sun.COM 	}
25877934SMark.Phalan@Sun.COM     }
25887934SMark.Phalan@Sun.COM     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
25897934SMark.Phalan@Sun.COM     if (aip == NULL)
25907934SMark.Phalan@Sun.COM 	return NULL;
25917934SMark.Phalan@Sun.COM     else {
25927934SMark.Phalan@Sun.COM 	(*a)->g = ASN1_INTEGER_to_BN(aip, NULL);
25937934SMark.Phalan@Sun.COM 	if ((*a)->g == NULL)
25947934SMark.Phalan@Sun.COM 	    return NULL;
25957934SMark.Phalan@Sun.COM 	if (ai.data != NULL) {
25967934SMark.Phalan@Sun.COM 	    OPENSSL_free(ai.data);
25977934SMark.Phalan@Sun.COM 	    ai.data = NULL;
25987934SMark.Phalan@Sun.COM 	    ai.length = 0;
25997934SMark.Phalan@Sun.COM 	}
26007934SMark.Phalan@Sun.COM 
26017934SMark.Phalan@Sun.COM     }
26027934SMark.Phalan@Sun.COM     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
26037934SMark.Phalan@Sun.COM     if (aip == NULL)
26047934SMark.Phalan@Sun.COM 	return NULL;
26057934SMark.Phalan@Sun.COM     else {
26067934SMark.Phalan@Sun.COM 	(*a)->q = ASN1_INTEGER_to_BN(aip, NULL);
26077934SMark.Phalan@Sun.COM 	if ((*a)->q == NULL)
26087934SMark.Phalan@Sun.COM 	    return NULL;
26097934SMark.Phalan@Sun.COM 	if (ai.data != NULL) {
26107934SMark.Phalan@Sun.COM 	    OPENSSL_free(ai.data);
26117934SMark.Phalan@Sun.COM 	    ai.data = NULL;
26127934SMark.Phalan@Sun.COM 	    ai.length = 0;
26137934SMark.Phalan@Sun.COM 	}
26147934SMark.Phalan@Sun.COM 
26157934SMark.Phalan@Sun.COM     }
26167934SMark.Phalan@Sun.COM     M_ASN1_D2I_end_sequence();
26177934SMark.Phalan@Sun.COM     M_ASN1_D2I_Finish(a, DH_free, 0);
26187934SMark.Phalan@Sun.COM 
26197934SMark.Phalan@Sun.COM }
26207934SMark.Phalan@Sun.COM 
26217934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_create_sequence_of_principal_identifiers(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int type,krb5_data ** out_data)26227934SMark.Phalan@Sun.COM pkinit_create_sequence_of_principal_identifiers(
26237934SMark.Phalan@Sun.COM     krb5_context context,
26247934SMark.Phalan@Sun.COM     pkinit_plg_crypto_context plg_cryptoctx,
26257934SMark.Phalan@Sun.COM     pkinit_req_crypto_context req_cryptoctx,
26267934SMark.Phalan@Sun.COM     pkinit_identity_crypto_context id_cryptoctx,
26277934SMark.Phalan@Sun.COM     int type,
26287934SMark.Phalan@Sun.COM     krb5_data **out_data)
26297934SMark.Phalan@Sun.COM {
26307934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
26317934SMark.Phalan@Sun.COM     krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
26327934SMark.Phalan@Sun.COM     krb5_data *td_certifiers = NULL, *data = NULL;
26337934SMark.Phalan@Sun.COM     krb5_typed_data **typed_data = NULL;
26347934SMark.Phalan@Sun.COM 
26357934SMark.Phalan@Sun.COM     switch(type) {
26367934SMark.Phalan@Sun.COM 	case TD_TRUSTED_CERTIFIERS:
26377934SMark.Phalan@Sun.COM 	    retval = create_krb5_trustedCertifiers(context, plg_cryptoctx,
26387934SMark.Phalan@Sun.COM 		req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
26397934SMark.Phalan@Sun.COM 	    if (retval) {
26407934SMark.Phalan@Sun.COM 		pkiDebug("create_krb5_trustedCertifiers failed\n");
26417934SMark.Phalan@Sun.COM 		goto cleanup;
26427934SMark.Phalan@Sun.COM     	    }
26437934SMark.Phalan@Sun.COM 	    break;
26447934SMark.Phalan@Sun.COM 	case TD_INVALID_CERTIFICATES:
26457934SMark.Phalan@Sun.COM 	    retval = create_krb5_invalidCertificates(context, plg_cryptoctx,
26467934SMark.Phalan@Sun.COM 		req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
26477934SMark.Phalan@Sun.COM 	    if (retval) {
26487934SMark.Phalan@Sun.COM 		pkiDebug("create_krb5_invalidCertificates failed\n");
26497934SMark.Phalan@Sun.COM 		goto cleanup;
26507934SMark.Phalan@Sun.COM     	    }
26517934SMark.Phalan@Sun.COM 	    break;
26527934SMark.Phalan@Sun.COM 	default:
26537934SMark.Phalan@Sun.COM 	    retval = -1;
26547934SMark.Phalan@Sun.COM 	    goto cleanup;
26557934SMark.Phalan@Sun.COM     }
26567934SMark.Phalan@Sun.COM 
26577934SMark.Phalan@Sun.COM     retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_trusted_certifiers, &td_certifiers);
26587934SMark.Phalan@Sun.COM     if (retval) {
26597934SMark.Phalan@Sun.COM 	pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
26607934SMark.Phalan@Sun.COM 	goto cleanup;
26617934SMark.Phalan@Sun.COM     }
26627934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
26637934SMark.Phalan@Sun.COM     print_buffer_bin((unsigned char *)td_certifiers->data,
26647934SMark.Phalan@Sun.COM 		     td_certifiers->length, "/tmp/kdc_td_certifiers");
26657934SMark.Phalan@Sun.COM #endif
26667934SMark.Phalan@Sun.COM     typed_data = malloc (2 * sizeof(krb5_typed_data *));
26677934SMark.Phalan@Sun.COM     if (typed_data == NULL) {
26687934SMark.Phalan@Sun.COM 	retval = ENOMEM;
26697934SMark.Phalan@Sun.COM 	goto cleanup;
26707934SMark.Phalan@Sun.COM     }
26717934SMark.Phalan@Sun.COM     typed_data[1] = NULL;
26727934SMark.Phalan@Sun.COM     init_krb5_typed_data(&typed_data[0]);
26737934SMark.Phalan@Sun.COM     if (typed_data[0] == NULL) {
26747934SMark.Phalan@Sun.COM 	retval = ENOMEM;
26757934SMark.Phalan@Sun.COM 	goto cleanup;
26767934SMark.Phalan@Sun.COM     }
26777934SMark.Phalan@Sun.COM     typed_data[0]->type = type;
26787934SMark.Phalan@Sun.COM     typed_data[0]->length = td_certifiers->length;
26797934SMark.Phalan@Sun.COM     typed_data[0]->data = (unsigned char *)td_certifiers->data;
26807934SMark.Phalan@Sun.COM     retval = k5int_encode_krb5_typed_data((const krb5_typed_data **)typed_data,
26817934SMark.Phalan@Sun.COM 					  &data);
26827934SMark.Phalan@Sun.COM     if (retval) {
26837934SMark.Phalan@Sun.COM 	pkiDebug("encode_krb5_typed_data failed\n");
26847934SMark.Phalan@Sun.COM 	goto cleanup;
26857934SMark.Phalan@Sun.COM     }
26867934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
26877934SMark.Phalan@Sun.COM     print_buffer_bin((unsigned char *)data->data, data->length,
26887934SMark.Phalan@Sun.COM 		     "/tmp/kdc_edata");
26897934SMark.Phalan@Sun.COM #endif
26907934SMark.Phalan@Sun.COM     *out_data = (krb5_data *)malloc(sizeof(krb5_data));
26917934SMark.Phalan@Sun.COM     (*out_data)->length = data->length;
26927934SMark.Phalan@Sun.COM     (*out_data)->data = (char *)malloc(data->length);
26937934SMark.Phalan@Sun.COM     (void) memcpy((*out_data)->data, data->data, data->length);
26947934SMark.Phalan@Sun.COM 
26957934SMark.Phalan@Sun.COM     retval = 0;
26967934SMark.Phalan@Sun.COM 
26977934SMark.Phalan@Sun.COM cleanup:
26987934SMark.Phalan@Sun.COM     if (krb5_trusted_certifiers != NULL)
26997934SMark.Phalan@Sun.COM 	free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
27007934SMark.Phalan@Sun.COM 
27017934SMark.Phalan@Sun.COM     if (data != NULL) {
27027934SMark.Phalan@Sun.COM 	if (data->data != NULL)
27037934SMark.Phalan@Sun.COM 	    free(data->data);
27047934SMark.Phalan@Sun.COM 	free(data);
27057934SMark.Phalan@Sun.COM     }
27067934SMark.Phalan@Sun.COM 
27077934SMark.Phalan@Sun.COM     if (td_certifiers != NULL)
27087934SMark.Phalan@Sun.COM 	free(td_certifiers);
27097934SMark.Phalan@Sun.COM 
27107934SMark.Phalan@Sun.COM     if (typed_data != NULL)
27117934SMark.Phalan@Sun.COM 	free_krb5_typed_data(&typed_data);
27127934SMark.Phalan@Sun.COM 
27137934SMark.Phalan@Sun.COM     return retval;
27147934SMark.Phalan@Sun.COM }
27157934SMark.Phalan@Sun.COM 
27167934SMark.Phalan@Sun.COM krb5_error_code
pkinit_create_td_trusted_certifiers(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_data ** out_data)27177934SMark.Phalan@Sun.COM pkinit_create_td_trusted_certifiers(krb5_context context,
27187934SMark.Phalan@Sun.COM 				    pkinit_plg_crypto_context plg_cryptoctx,
27197934SMark.Phalan@Sun.COM 				    pkinit_req_crypto_context req_cryptoctx,
27207934SMark.Phalan@Sun.COM 				    pkinit_identity_crypto_context id_cryptoctx,
27217934SMark.Phalan@Sun.COM 				    krb5_data **out_data)
27227934SMark.Phalan@Sun.COM {
27237934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
27247934SMark.Phalan@Sun.COM 
27257934SMark.Phalan@Sun.COM     retval = pkinit_create_sequence_of_principal_identifiers(context,
27267934SMark.Phalan@Sun.COM 	plg_cryptoctx, req_cryptoctx, id_cryptoctx,
27277934SMark.Phalan@Sun.COM 	TD_TRUSTED_CERTIFIERS, out_data);
27287934SMark.Phalan@Sun.COM 
27297934SMark.Phalan@Sun.COM     return retval;
27307934SMark.Phalan@Sun.COM }
27317934SMark.Phalan@Sun.COM 
27327934SMark.Phalan@Sun.COM krb5_error_code
pkinit_create_td_invalid_certificate(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_data ** out_data)27337934SMark.Phalan@Sun.COM pkinit_create_td_invalid_certificate(
27347934SMark.Phalan@Sun.COM 	krb5_context context,
27357934SMark.Phalan@Sun.COM 	pkinit_plg_crypto_context plg_cryptoctx,
27367934SMark.Phalan@Sun.COM 	pkinit_req_crypto_context req_cryptoctx,
27377934SMark.Phalan@Sun.COM 	pkinit_identity_crypto_context id_cryptoctx,
27387934SMark.Phalan@Sun.COM 	krb5_data **out_data)
27397934SMark.Phalan@Sun.COM {
27407934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
27417934SMark.Phalan@Sun.COM 
27427934SMark.Phalan@Sun.COM     retval = pkinit_create_sequence_of_principal_identifiers(context,
27437934SMark.Phalan@Sun.COM 	plg_cryptoctx, req_cryptoctx, id_cryptoctx,
27447934SMark.Phalan@Sun.COM 	TD_INVALID_CERTIFICATES, out_data);
27457934SMark.Phalan@Sun.COM 
27467934SMark.Phalan@Sun.COM     return retval;
27477934SMark.Phalan@Sun.COM }
27487934SMark.Phalan@Sun.COM 
27497934SMark.Phalan@Sun.COM /* ARGSUSED */
27507934SMark.Phalan@Sun.COM krb5_error_code
pkinit_create_td_dh_parameters(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,pkinit_plg_opts * opts,krb5_data ** out_data)27517934SMark.Phalan@Sun.COM pkinit_create_td_dh_parameters(krb5_context context,
27527934SMark.Phalan@Sun.COM 			       pkinit_plg_crypto_context plg_cryptoctx,
27537934SMark.Phalan@Sun.COM 			       pkinit_req_crypto_context req_cryptoctx,
27547934SMark.Phalan@Sun.COM 			       pkinit_identity_crypto_context id_cryptoctx,
27557934SMark.Phalan@Sun.COM 			       pkinit_plg_opts *opts,
27567934SMark.Phalan@Sun.COM 			       krb5_data **out_data)
27577934SMark.Phalan@Sun.COM {
27587934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
27597934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
27607934SMark.Phalan@Sun.COM     unsigned int buf1_len = 0, buf2_len = 0, buf3_len = 0, i = 0;
27617934SMark.Phalan@Sun.COM     unsigned char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
27627934SMark.Phalan@Sun.COM     krb5_typed_data **typed_data = NULL;
27637934SMark.Phalan@Sun.COM     krb5_data *data = NULL, *encoded_algId = NULL;
27647934SMark.Phalan@Sun.COM     krb5_algorithm_identifier **algId = NULL;
27657934SMark.Phalan@Sun.COM 
27667934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
27677934SMark.Phalan@Sun.COM     if (opts->dh_min_bits > 4096) {
27687934SMark.Phalan@Sun.COM 	retval = EINVAL;
27697934SMark.Phalan@Sun.COM 	goto cleanup;
27707934SMark.Phalan@Sun.COM     }
27717934SMark.Phalan@Sun.COM 
27727934SMark.Phalan@Sun.COM     if (opts->dh_min_bits <= 1024) {
27737934SMark.Phalan@Sun.COM 	retval = pkinit_encode_dh_params(plg_cryptoctx->dh_1024->p,
27747934SMark.Phalan@Sun.COM 	    plg_cryptoctx->dh_1024->g, plg_cryptoctx->dh_1024->q,
27757934SMark.Phalan@Sun.COM 	    &buf1, &buf1_len);
27767934SMark.Phalan@Sun.COM 	if (retval)
27777934SMark.Phalan@Sun.COM 	    goto cleanup;
27787934SMark.Phalan@Sun.COM     }
27797934SMark.Phalan@Sun.COM     if (opts->dh_min_bits <= 2048) {
27807934SMark.Phalan@Sun.COM 	retval = pkinit_encode_dh_params(plg_cryptoctx->dh_2048->p,
27817934SMark.Phalan@Sun.COM 	    plg_cryptoctx->dh_2048->g, plg_cryptoctx->dh_2048->q,
27827934SMark.Phalan@Sun.COM 	    &buf2, &buf2_len);
27837934SMark.Phalan@Sun.COM 	if (retval)
27847934SMark.Phalan@Sun.COM 	    goto cleanup;
27857934SMark.Phalan@Sun.COM     }
27867934SMark.Phalan@Sun.COM     retval = pkinit_encode_dh_params(plg_cryptoctx->dh_4096->p,
27877934SMark.Phalan@Sun.COM 	plg_cryptoctx->dh_4096->g, plg_cryptoctx->dh_4096->q,
27887934SMark.Phalan@Sun.COM 	&buf3, &buf3_len);
27897934SMark.Phalan@Sun.COM     if (retval)
27907934SMark.Phalan@Sun.COM 	goto cleanup;
27917934SMark.Phalan@Sun.COM 
27927934SMark.Phalan@Sun.COM     if (opts->dh_min_bits <= 1024) {
27937934SMark.Phalan@Sun.COM 	algId = malloc(4 * sizeof(krb5_algorithm_identifier *));
27947934SMark.Phalan@Sun.COM 	if (algId == NULL)
27957934SMark.Phalan@Sun.COM 	    goto cleanup;
27967934SMark.Phalan@Sun.COM 	algId[3] = NULL;
27977934SMark.Phalan@Sun.COM 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
27987934SMark.Phalan@Sun.COM 	if (algId[0] == NULL)
27997934SMark.Phalan@Sun.COM 	    goto cleanup;
28007934SMark.Phalan@Sun.COM 	algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
28017934SMark.Phalan@Sun.COM 	if (algId[0]->parameters.data == NULL)
28027934SMark.Phalan@Sun.COM 	    goto cleanup;
28037934SMark.Phalan@Sun.COM 	(void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
28047934SMark.Phalan@Sun.COM 	algId[0]->parameters.length = buf2_len;
28057934SMark.Phalan@Sun.COM 	algId[0]->algorithm = dh_oid;
28067934SMark.Phalan@Sun.COM 
28077934SMark.Phalan@Sun.COM 	algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
28087934SMark.Phalan@Sun.COM 	if (algId[1] == NULL)
28097934SMark.Phalan@Sun.COM 	    goto cleanup;
28107934SMark.Phalan@Sun.COM 	algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
28117934SMark.Phalan@Sun.COM 	if (algId[1]->parameters.data == NULL)
28127934SMark.Phalan@Sun.COM 	    goto cleanup;
28137934SMark.Phalan@Sun.COM 	(void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
28147934SMark.Phalan@Sun.COM 	algId[1]->parameters.length = buf3_len;
28157934SMark.Phalan@Sun.COM 	algId[1]->algorithm = dh_oid;
28167934SMark.Phalan@Sun.COM 
28177934SMark.Phalan@Sun.COM 	algId[2] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
28187934SMark.Phalan@Sun.COM 	if (algId[2] == NULL)
28197934SMark.Phalan@Sun.COM 	    goto cleanup;
28207934SMark.Phalan@Sun.COM 	algId[2]->parameters.data = (unsigned char *)malloc(buf1_len);
28217934SMark.Phalan@Sun.COM 	if (algId[2]->parameters.data == NULL)
28227934SMark.Phalan@Sun.COM 	    goto cleanup;
28237934SMark.Phalan@Sun.COM 	(void) memcpy(algId[2]->parameters.data, buf1, buf1_len);
28247934SMark.Phalan@Sun.COM 	algId[2]->parameters.length = buf1_len;
28257934SMark.Phalan@Sun.COM 	algId[2]->algorithm = dh_oid;
28267934SMark.Phalan@Sun.COM 
28277934SMark.Phalan@Sun.COM     } else if (opts->dh_min_bits <= 2048) {
28287934SMark.Phalan@Sun.COM 	algId = malloc(3 * sizeof(krb5_algorithm_identifier *));
28297934SMark.Phalan@Sun.COM 	if (algId == NULL)
28307934SMark.Phalan@Sun.COM 	    goto cleanup;
28317934SMark.Phalan@Sun.COM 	algId[2] = NULL;
28327934SMark.Phalan@Sun.COM 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
28337934SMark.Phalan@Sun.COM 	if (algId[0] == NULL)
28347934SMark.Phalan@Sun.COM 	    goto cleanup;
28357934SMark.Phalan@Sun.COM 	algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
28367934SMark.Phalan@Sun.COM 	if (algId[0]->parameters.data == NULL)
28377934SMark.Phalan@Sun.COM 	    goto cleanup;
28387934SMark.Phalan@Sun.COM 	(void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
28397934SMark.Phalan@Sun.COM 	algId[0]->parameters.length = buf2_len;
28407934SMark.Phalan@Sun.COM 	algId[0]->algorithm = dh_oid;
28417934SMark.Phalan@Sun.COM 
28427934SMark.Phalan@Sun.COM 	algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
28437934SMark.Phalan@Sun.COM 	if (algId[1] == NULL)
28447934SMark.Phalan@Sun.COM 	    goto cleanup;
28457934SMark.Phalan@Sun.COM 	algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
28467934SMark.Phalan@Sun.COM 	if (algId[1]->parameters.data == NULL)
28477934SMark.Phalan@Sun.COM 	    goto cleanup;
28487934SMark.Phalan@Sun.COM 	(void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
28497934SMark.Phalan@Sun.COM 	algId[1]->parameters.length = buf3_len;
28507934SMark.Phalan@Sun.COM 	algId[1]->algorithm = dh_oid;
28517934SMark.Phalan@Sun.COM 
28527934SMark.Phalan@Sun.COM     } else if (opts->dh_min_bits <= 4096) {
28537934SMark.Phalan@Sun.COM 	algId = malloc(2 * sizeof(krb5_algorithm_identifier *));
28547934SMark.Phalan@Sun.COM 	if (algId == NULL)
28557934SMark.Phalan@Sun.COM 	    goto cleanup;
28567934SMark.Phalan@Sun.COM 	algId[1] = NULL;
28577934SMark.Phalan@Sun.COM 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
28587934SMark.Phalan@Sun.COM 	if (algId[0] == NULL)
28597934SMark.Phalan@Sun.COM 	    goto cleanup;
28607934SMark.Phalan@Sun.COM 	algId[0]->parameters.data = (unsigned char *)malloc(buf3_len);
28617934SMark.Phalan@Sun.COM 	if (algId[0]->parameters.data == NULL)
28627934SMark.Phalan@Sun.COM 	    goto cleanup;
28637934SMark.Phalan@Sun.COM 	(void) memcpy(algId[0]->parameters.data, buf3, buf3_len);
28647934SMark.Phalan@Sun.COM 	algId[0]->parameters.length = buf3_len;
28657934SMark.Phalan@Sun.COM 	algId[0]->algorithm = dh_oid;
28667934SMark.Phalan@Sun.COM 
28677934SMark.Phalan@Sun.COM     }
28687934SMark.Phalan@Sun.COM     retval = k5int_encode_krb5_td_dh_parameters((const krb5_algorithm_identifier **)algId, &encoded_algId);
28697934SMark.Phalan@Sun.COM     if (retval)
28707934SMark.Phalan@Sun.COM 	goto cleanup;
28717934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
28727934SMark.Phalan@Sun.COM     print_buffer_bin((unsigned char *)encoded_algId->data,
28737934SMark.Phalan@Sun.COM 		     encoded_algId->length, "/tmp/kdc_td_dh_params");
28747934SMark.Phalan@Sun.COM #endif
28757934SMark.Phalan@Sun.COM     typed_data = malloc (2 * sizeof(krb5_typed_data *));
28767934SMark.Phalan@Sun.COM     if (typed_data == NULL) {
28777934SMark.Phalan@Sun.COM 	retval = ENOMEM;
28787934SMark.Phalan@Sun.COM 	goto cleanup;
28797934SMark.Phalan@Sun.COM     }
28807934SMark.Phalan@Sun.COM     typed_data[1] = NULL;
28817934SMark.Phalan@Sun.COM     init_krb5_typed_data(&typed_data[0]);
28827934SMark.Phalan@Sun.COM     if (typed_data == NULL) {
28837934SMark.Phalan@Sun.COM 	retval = ENOMEM;
28847934SMark.Phalan@Sun.COM 	goto cleanup;
28857934SMark.Phalan@Sun.COM     }
28867934SMark.Phalan@Sun.COM     typed_data[0]->type = TD_DH_PARAMETERS;
28877934SMark.Phalan@Sun.COM     typed_data[0]->length = encoded_algId->length;
28887934SMark.Phalan@Sun.COM     typed_data[0]->data = (unsigned char *)encoded_algId->data;
28897934SMark.Phalan@Sun.COM     retval = k5int_encode_krb5_typed_data((const krb5_typed_data**)typed_data,
28907934SMark.Phalan@Sun.COM 					  &data);
28917934SMark.Phalan@Sun.COM     if (retval) {
28927934SMark.Phalan@Sun.COM 	pkiDebug("encode_krb5_typed_data failed\n");
28937934SMark.Phalan@Sun.COM 	goto cleanup;
28947934SMark.Phalan@Sun.COM     }
28957934SMark.Phalan@Sun.COM #ifdef DEBUG_ASN1
28967934SMark.Phalan@Sun.COM     print_buffer_bin((unsigned char *)data->data, data->length,
28977934SMark.Phalan@Sun.COM 		     "/tmp/kdc_edata");
28987934SMark.Phalan@Sun.COM #endif
28997934SMark.Phalan@Sun.COM     *out_data = (krb5_data *)malloc(sizeof(krb5_data));
29007934SMark.Phalan@Sun.COM     if (*out_data == NULL)
29017934SMark.Phalan@Sun.COM 	goto cleanup;
29027934SMark.Phalan@Sun.COM     (*out_data)->length = data->length;
29037934SMark.Phalan@Sun.COM     (*out_data)->data = (char *)malloc(data->length);
29047934SMark.Phalan@Sun.COM     if ((*out_data)->data == NULL) {
29057934SMark.Phalan@Sun.COM 	free(*out_data);
29067934SMark.Phalan@Sun.COM 	*out_data = NULL;
29077934SMark.Phalan@Sun.COM 	goto cleanup;
29087934SMark.Phalan@Sun.COM     }
29097934SMark.Phalan@Sun.COM     (void) memcpy((*out_data)->data, data->data, data->length);
29107934SMark.Phalan@Sun.COM 
29117934SMark.Phalan@Sun.COM     retval = 0;
29127934SMark.Phalan@Sun.COM cleanup:
29137934SMark.Phalan@Sun.COM 
29147934SMark.Phalan@Sun.COM     if (buf1 != NULL)
29157934SMark.Phalan@Sun.COM 	free(buf1);
29167934SMark.Phalan@Sun.COM     if (buf2 != NULL)
29177934SMark.Phalan@Sun.COM 	free(buf2);
29187934SMark.Phalan@Sun.COM     if (buf3 != NULL)
29197934SMark.Phalan@Sun.COM 	free(buf3);
29207934SMark.Phalan@Sun.COM     if (data != NULL) {
29217934SMark.Phalan@Sun.COM 	if (data->data != NULL)
29227934SMark.Phalan@Sun.COM 	    free(data->data);
29237934SMark.Phalan@Sun.COM 	free(data);
29247934SMark.Phalan@Sun.COM     }
29257934SMark.Phalan@Sun.COM     if (typed_data != NULL)
29267934SMark.Phalan@Sun.COM 	free_krb5_typed_data(&typed_data);
29277934SMark.Phalan@Sun.COM     if (encoded_algId != NULL)
29287934SMark.Phalan@Sun.COM 	free(encoded_algId);
29297934SMark.Phalan@Sun.COM 
29307934SMark.Phalan@Sun.COM     if (algId != NULL) {
29317934SMark.Phalan@Sun.COM 	while(algId[i] != NULL) {
29327934SMark.Phalan@Sun.COM 	    if (algId[i]->parameters.data != NULL)
29337934SMark.Phalan@Sun.COM 		free(algId[i]->parameters.data);
29347934SMark.Phalan@Sun.COM 	    free(algId[i]);
29357934SMark.Phalan@Sun.COM 	    i++;
29367934SMark.Phalan@Sun.COM 	}
29377934SMark.Phalan@Sun.COM 	free(algId);
29387934SMark.Phalan@Sun.COM     }
29397934SMark.Phalan@Sun.COM 
29407934SMark.Phalan@Sun.COM     return retval;
29417934SMark.Phalan@Sun.COM }
29427934SMark.Phalan@Sun.COM 
29437934SMark.Phalan@Sun.COM /* ARGSUSED */
29447934SMark.Phalan@Sun.COM krb5_error_code
pkinit_check_kdc_pkid(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char * pdid_buf,unsigned int pkid_len,int * valid_kdcPkId)29457934SMark.Phalan@Sun.COM pkinit_check_kdc_pkid(krb5_context context,
29467934SMark.Phalan@Sun.COM 		      pkinit_plg_crypto_context plg_cryptoctx,
29477934SMark.Phalan@Sun.COM 		      pkinit_req_crypto_context req_cryptoctx,
29487934SMark.Phalan@Sun.COM 		      pkinit_identity_crypto_context id_cryptoctx,
29497934SMark.Phalan@Sun.COM 		      unsigned char *pdid_buf,
29507934SMark.Phalan@Sun.COM 		      unsigned int pkid_len,
29517934SMark.Phalan@Sun.COM 		      int *valid_kdcPkId)
29527934SMark.Phalan@Sun.COM {
29537934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
29547934SMark.Phalan@Sun.COM     PKCS7_ISSUER_AND_SERIAL *is = NULL;
29557934SMark.Phalan@Sun.COM     const unsigned char *p = pdid_buf;
29567934SMark.Phalan@Sun.COM     int status = 1;
29577934SMark.Phalan@Sun.COM     X509 *kdc_cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
29587934SMark.Phalan@Sun.COM 
29597934SMark.Phalan@Sun.COM     *valid_kdcPkId = 0;
29607934SMark.Phalan@Sun.COM     pkiDebug("found kdcPkId in AS REQ\n");
29617934SMark.Phalan@Sun.COM     is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p, (int)pkid_len);
29627934SMark.Phalan@Sun.COM     if (is == NULL)
29637934SMark.Phalan@Sun.COM 	goto cleanup;
29647934SMark.Phalan@Sun.COM 
29657934SMark.Phalan@Sun.COM     status = X509_NAME_cmp(X509_get_issuer_name(kdc_cert), is->issuer);
29667934SMark.Phalan@Sun.COM     if (!status) {
29677934SMark.Phalan@Sun.COM 	status = ASN1_INTEGER_cmp(X509_get_serialNumber(kdc_cert), is->serial);
29687934SMark.Phalan@Sun.COM 	if (!status)
29697934SMark.Phalan@Sun.COM 	    *valid_kdcPkId = 1;
29707934SMark.Phalan@Sun.COM     }
29717934SMark.Phalan@Sun.COM 
29727934SMark.Phalan@Sun.COM     retval = 0;
29737934SMark.Phalan@Sun.COM cleanup:
29747934SMark.Phalan@Sun.COM     X509_NAME_free(is->issuer);
29757934SMark.Phalan@Sun.COM     ASN1_INTEGER_free(is->serial);
29767934SMark.Phalan@Sun.COM     free(is);
29777934SMark.Phalan@Sun.COM 
29787934SMark.Phalan@Sun.COM     return retval;
29797934SMark.Phalan@Sun.COM }
29807934SMark.Phalan@Sun.COM 
29817934SMark.Phalan@Sun.COM static int
pkinit_check_dh_params(BIGNUM * p1,BIGNUM * p2,BIGNUM * g1,BIGNUM * q1)29827934SMark.Phalan@Sun.COM pkinit_check_dh_params(BIGNUM * p1, BIGNUM * p2, BIGNUM * g1, BIGNUM * q1)
29837934SMark.Phalan@Sun.COM {
29847934SMark.Phalan@Sun.COM     BIGNUM *g2 = NULL, *q2 = NULL;
29857934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
29867934SMark.Phalan@Sun.COM     int retval = EINVAL;
29877934SMark.Phalan@Sun.COM 
29887934SMark.Phalan@Sun.COM     if (!BN_cmp(p1, p2)) {
29897934SMark.Phalan@Sun.COM 	g2 = BN_new();
29907934SMark.Phalan@Sun.COM 	BN_set_word(g2, DH_GENERATOR_2);
29917934SMark.Phalan@Sun.COM 	if (!BN_cmp(g1, g2)) {
29927934SMark.Phalan@Sun.COM 	    q2 = BN_new();
29937934SMark.Phalan@Sun.COM 	    BN_rshift1(q2, p1);
29947934SMark.Phalan@Sun.COM 	    if (!BN_cmp(q1, q2)) {
29957934SMark.Phalan@Sun.COM 		pkiDebug("good %d dhparams\n", BN_num_bits(p1));
29967934SMark.Phalan@Sun.COM 		retval = 0;
29977934SMark.Phalan@Sun.COM 	    } else
29987934SMark.Phalan@Sun.COM 		pkiDebug("bad group 2 q dhparameter\n");
29997934SMark.Phalan@Sun.COM 	    BN_free(q2);
30007934SMark.Phalan@Sun.COM 	} else
30017934SMark.Phalan@Sun.COM 	    pkiDebug("bad g dhparameter\n");
30027934SMark.Phalan@Sun.COM 	BN_free(g2);
30037934SMark.Phalan@Sun.COM     } else
30047934SMark.Phalan@Sun.COM 	pkiDebug("p is not well-known group 2 dhparameter\n");
30057934SMark.Phalan@Sun.COM 
30067934SMark.Phalan@Sun.COM     return retval;
30077934SMark.Phalan@Sun.COM }
30087934SMark.Phalan@Sun.COM 
30097934SMark.Phalan@Sun.COM /* ARGSUSED */
30107934SMark.Phalan@Sun.COM krb5_error_code
pkinit_process_td_dh_params(krb5_context context,pkinit_plg_crypto_context cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_algorithm_identifier ** algId,int * new_dh_size)30117934SMark.Phalan@Sun.COM pkinit_process_td_dh_params(krb5_context context,
30127934SMark.Phalan@Sun.COM 			    pkinit_plg_crypto_context cryptoctx,
30137934SMark.Phalan@Sun.COM 			    pkinit_req_crypto_context req_cryptoctx,
30147934SMark.Phalan@Sun.COM 			    pkinit_identity_crypto_context id_cryptoctx,
30157934SMark.Phalan@Sun.COM 			    krb5_algorithm_identifier **algId,
30167934SMark.Phalan@Sun.COM 			    int *new_dh_size)
30177934SMark.Phalan@Sun.COM {
30187934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
30197934SMark.Phalan@Sun.COM     int i = 0, use_sent_dh = 0, ok = 0;
30207934SMark.Phalan@Sun.COM 
30217934SMark.Phalan@Sun.COM     pkiDebug("dh parameters\n");
30227934SMark.Phalan@Sun.COM 
30237934SMark.Phalan@Sun.COM     while (algId[i] != NULL) {
30247934SMark.Phalan@Sun.COM 	DH *dh = NULL;
30257934SMark.Phalan@Sun.COM 	unsigned char *tmp = NULL;
30267934SMark.Phalan@Sun.COM 	int dh_prime_bits = 0;
30277934SMark.Phalan@Sun.COM 
30287934SMark.Phalan@Sun.COM 	if (algId[i]->algorithm.length != dh_oid.length ||
30297934SMark.Phalan@Sun.COM 	    memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
30307934SMark.Phalan@Sun.COM 	    goto cleanup;
30317934SMark.Phalan@Sun.COM 
30327934SMark.Phalan@Sun.COM 	tmp = algId[i]->parameters.data;
30337934SMark.Phalan@Sun.COM 	dh = DH_new();
30347934SMark.Phalan@Sun.COM 	dh = pkinit_decode_dh_params(&dh, &tmp, algId[i]->parameters.length);
30357934SMark.Phalan@Sun.COM 	dh_prime_bits = BN_num_bits(dh->p);
30367934SMark.Phalan@Sun.COM 	pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
30377934SMark.Phalan@Sun.COM 		 *new_dh_size, dh_prime_bits);
30387934SMark.Phalan@Sun.COM 	switch(dh_prime_bits) {
30397934SMark.Phalan@Sun.COM 	    case 1024:
30407934SMark.Phalan@Sun.COM 		if (pkinit_check_dh_params(cryptoctx->dh_1024->p, dh->p,
30417934SMark.Phalan@Sun.COM 			dh->g, dh->q) == 0) {
30427934SMark.Phalan@Sun.COM 		    *new_dh_size = 1024;
30437934SMark.Phalan@Sun.COM 		    ok = 1;
30447934SMark.Phalan@Sun.COM 		}
30457934SMark.Phalan@Sun.COM 		break;
30467934SMark.Phalan@Sun.COM 	    case 2048:
30477934SMark.Phalan@Sun.COM 		if (pkinit_check_dh_params(cryptoctx->dh_2048->p, dh->p,
30487934SMark.Phalan@Sun.COM 			dh->g, dh->q) == 0) {
30497934SMark.Phalan@Sun.COM 		    *new_dh_size = 2048;
30507934SMark.Phalan@Sun.COM 		    ok = 1;
30517934SMark.Phalan@Sun.COM 		}
30527934SMark.Phalan@Sun.COM 		break;
30537934SMark.Phalan@Sun.COM 	    case 4096:
30547934SMark.Phalan@Sun.COM 		if (pkinit_check_dh_params(cryptoctx->dh_4096->p, dh->p,
30557934SMark.Phalan@Sun.COM 			dh->g, dh->q) == 0) {
30567934SMark.Phalan@Sun.COM 		    *new_dh_size = 4096;
30577934SMark.Phalan@Sun.COM 		    ok = 1;
30587934SMark.Phalan@Sun.COM 		}
30597934SMark.Phalan@Sun.COM 		break;
30607934SMark.Phalan@Sun.COM 	    default:
30617934SMark.Phalan@Sun.COM 		break;
30627934SMark.Phalan@Sun.COM 	}
30637934SMark.Phalan@Sun.COM 	if (!ok) {
30647934SMark.Phalan@Sun.COM 	    DH_check(dh, &retval);
30657934SMark.Phalan@Sun.COM 	    if (retval != 0) {
30667934SMark.Phalan@Sun.COM 		pkiDebug("DH parameters provided by server are unacceptable\n");
30677934SMark.Phalan@Sun.COM 		retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
30687934SMark.Phalan@Sun.COM 	    }
30697934SMark.Phalan@Sun.COM 	    else {
30707934SMark.Phalan@Sun.COM 		use_sent_dh = 1;
30717934SMark.Phalan@Sun.COM 		ok = 1;
30727934SMark.Phalan@Sun.COM 	    }
30737934SMark.Phalan@Sun.COM 	}
30747934SMark.Phalan@Sun.COM 	if (!use_sent_dh)
30757934SMark.Phalan@Sun.COM 	    DH_free(dh);
30767934SMark.Phalan@Sun.COM 	if (ok) {
30777934SMark.Phalan@Sun.COM 	    if (req_cryptoctx->dh != NULL) {
30787934SMark.Phalan@Sun.COM 		DH_free(req_cryptoctx->dh);
30797934SMark.Phalan@Sun.COM 		req_cryptoctx->dh = NULL;
30807934SMark.Phalan@Sun.COM 	    }
30817934SMark.Phalan@Sun.COM 	    if (use_sent_dh)
30827934SMark.Phalan@Sun.COM 		req_cryptoctx->dh = dh;
30837934SMark.Phalan@Sun.COM 	    break;
30847934SMark.Phalan@Sun.COM 	}
30857934SMark.Phalan@Sun.COM 	i++;
30867934SMark.Phalan@Sun.COM     }
30877934SMark.Phalan@Sun.COM 
30887934SMark.Phalan@Sun.COM     if (ok)
30897934SMark.Phalan@Sun.COM 	retval = 0;
30907934SMark.Phalan@Sun.COM 
30917934SMark.Phalan@Sun.COM cleanup:
30927934SMark.Phalan@Sun.COM     return retval;
30937934SMark.Phalan@Sun.COM }
30947934SMark.Phalan@Sun.COM 
30957934SMark.Phalan@Sun.COM /* ARGSUSED */
30967934SMark.Phalan@Sun.COM static int
openssl_callback(int ok,X509_STORE_CTX * ctx)30977934SMark.Phalan@Sun.COM openssl_callback(int ok, X509_STORE_CTX * ctx)
30987934SMark.Phalan@Sun.COM {
30997934SMark.Phalan@Sun.COM #ifdef DEBUG
31007934SMark.Phalan@Sun.COM     if (!ok) {
31017934SMark.Phalan@Sun.COM 	char buf[DN_BUF_LEN];
31027934SMark.Phalan@Sun.COM 
31037934SMark.Phalan@Sun.COM 	X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf));
31047934SMark.Phalan@Sun.COM 	pkiDebug("cert = %s\n", buf);
31057934SMark.Phalan@Sun.COM 	pkiDebug("callback function: %d (%s)\n", ctx->error,
31067934SMark.Phalan@Sun.COM 		X509_verify_cert_error_string(ctx->error));
31077934SMark.Phalan@Sun.COM     }
31087934SMark.Phalan@Sun.COM #endif
31097934SMark.Phalan@Sun.COM     return ok;
31107934SMark.Phalan@Sun.COM }
31117934SMark.Phalan@Sun.COM 
31127934SMark.Phalan@Sun.COM static int
openssl_callback_ignore_crls(int ok,X509_STORE_CTX * ctx)31137934SMark.Phalan@Sun.COM openssl_callback_ignore_crls(int ok, X509_STORE_CTX * ctx)
31147934SMark.Phalan@Sun.COM {
31157934SMark.Phalan@Sun.COM     if (!ok) {
31167934SMark.Phalan@Sun.COM 	switch (ctx->error) {
31177934SMark.Phalan@Sun.COM 	    case X509_V_ERR_UNABLE_TO_GET_CRL:
31187934SMark.Phalan@Sun.COM 		return 1;
31197934SMark.Phalan@Sun.COM 	    default:
31207934SMark.Phalan@Sun.COM 		return 0;
31217934SMark.Phalan@Sun.COM 	}
31227934SMark.Phalan@Sun.COM     }
31237934SMark.Phalan@Sun.COM     return ok;
31247934SMark.Phalan@Sun.COM }
31257934SMark.Phalan@Sun.COM 
31267934SMark.Phalan@Sun.COM static ASN1_OBJECT *
pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx,int pkcs7_type)31277934SMark.Phalan@Sun.COM pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
31287934SMark.Phalan@Sun.COM {
31297934SMark.Phalan@Sun.COM     int nid;
31307934SMark.Phalan@Sun.COM 
31317934SMark.Phalan@Sun.COM     switch (pkcs7_type) {
31327934SMark.Phalan@Sun.COM 	case CMS_SIGN_CLIENT:
31337934SMark.Phalan@Sun.COM 	    return cryptoctx->id_pkinit_authData;
31347934SMark.Phalan@Sun.COM 	case CMS_SIGN_DRAFT9:
31357934SMark.Phalan@Sun.COM 	    /*
31367934SMark.Phalan@Sun.COM 	     * Delay creating this OID until we know we need it.
31377934SMark.Phalan@Sun.COM 	     * It shadows an existing OpenSSL oid.  If it
31387934SMark.Phalan@Sun.COM 	     * is created too early, it breaks things like
31397934SMark.Phalan@Sun.COM 	     * the use of pkcs12 (which uses pkcs7 structures).
31407934SMark.Phalan@Sun.COM 	     * We need this shadow version because our code
31417934SMark.Phalan@Sun.COM 	     * depends on the "other" type to be unknown to the
31427934SMark.Phalan@Sun.COM 	     * OpenSSL code.
31437934SMark.Phalan@Sun.COM 	     */
31447934SMark.Phalan@Sun.COM 	    if (cryptoctx->id_pkinit_authData9 == NULL) {
31457934SMark.Phalan@Sun.COM 		pkiDebug("%s: Creating shadow instance of pkcs7-data oid\n",
31467934SMark.Phalan@Sun.COM 			 __FUNCTION__);
31477934SMark.Phalan@Sun.COM 		nid = OBJ_create("1.2.840.113549.1.7.1", "id-pkcs7-data",
31487934SMark.Phalan@Sun.COM 				 "PKCS7 data");
31497934SMark.Phalan@Sun.COM 		if (nid == NID_undef)
31507934SMark.Phalan@Sun.COM 		    return NULL;
31517934SMark.Phalan@Sun.COM 		cryptoctx->id_pkinit_authData9 = OBJ_nid2obj(nid);
31527934SMark.Phalan@Sun.COM 	    }
31537934SMark.Phalan@Sun.COM 	    return cryptoctx->id_pkinit_authData9;
31547934SMark.Phalan@Sun.COM 	case CMS_SIGN_SERVER:
31557934SMark.Phalan@Sun.COM 	    return cryptoctx->id_pkinit_DHKeyData;
31567934SMark.Phalan@Sun.COM 	case CMS_ENVEL_SERVER:
31577934SMark.Phalan@Sun.COM 	    return cryptoctx->id_pkinit_rkeyData;
31587934SMark.Phalan@Sun.COM 	default:
31597934SMark.Phalan@Sun.COM 	    return NULL;
31607934SMark.Phalan@Sun.COM     }
31617934SMark.Phalan@Sun.COM 
31627934SMark.Phalan@Sun.COM }
31637934SMark.Phalan@Sun.COM 
31647934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
31657934SMark.Phalan@Sun.COM #if 0
31667934SMark.Phalan@Sun.COM /*
31677934SMark.Phalan@Sun.COM  * This is a version that worked with Longhorn Beta 3.
31687934SMark.Phalan@Sun.COM  */
31697934SMark.Phalan@Sun.COM static int
31707934SMark.Phalan@Sun.COM wrap_signeddata(unsigned char *data, unsigned int data_len,
31717934SMark.Phalan@Sun.COM 		unsigned char **out, unsigned int *out_len,
31727934SMark.Phalan@Sun.COM 		int is_longhorn_server)
31737934SMark.Phalan@Sun.COM {
31747934SMark.Phalan@Sun.COM 
31757934SMark.Phalan@Sun.COM     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
31767934SMark.Phalan@Sun.COM     ASN1_OBJECT *oid = NULL;
31777934SMark.Phalan@Sun.COM     unsigned char *p = NULL;
31787934SMark.Phalan@Sun.COM 
31797934SMark.Phalan@Sun.COM     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
31807934SMark.Phalan@Sun.COM 	     __FUNCTION__, is_longhorn_server);
31817934SMark.Phalan@Sun.COM 
31827934SMark.Phalan@Sun.COM     /* Get length to wrap the original data with SEQUENCE tag */
31837934SMark.Phalan@Sun.COM     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
31847934SMark.Phalan@Sun.COM 
31857934SMark.Phalan@Sun.COM     if (is_longhorn_server == 0) {
31867934SMark.Phalan@Sun.COM 	/* Add the signedData OID and adjust lengths */
31877934SMark.Phalan@Sun.COM 	oid = OBJ_nid2obj(NID_pkcs7_signed);
31887934SMark.Phalan@Sun.COM 	oid_len = i2d_ASN1_OBJECT(oid, NULL);
31897934SMark.Phalan@Sun.COM 
31907934SMark.Phalan@Sun.COM 	tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
31917934SMark.Phalan@Sun.COM     }
31927934SMark.Phalan@Sun.COM 
31937934SMark.Phalan@Sun.COM     p = *out = (unsigned char *)malloc(tot_len);
31947934SMark.Phalan@Sun.COM     if (p == NULL) return -1;
31957934SMark.Phalan@Sun.COM 
31967934SMark.Phalan@Sun.COM     if (is_longhorn_server == 0) {
31977934SMark.Phalan@Sun.COM 	ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
31987934SMark.Phalan@Sun.COM 			V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
31997934SMark.Phalan@Sun.COM 
32007934SMark.Phalan@Sun.COM 	i2d_ASN1_OBJECT(oid, &p);
32017934SMark.Phalan@Sun.COM 
32027934SMark.Phalan@Sun.COM 	ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
32037934SMark.Phalan@Sun.COM     } else {
32047934SMark.Phalan@Sun.COM 	ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
32057934SMark.Phalan@Sun.COM     }
32067934SMark.Phalan@Sun.COM     memcpy(p, data, data_len);
32077934SMark.Phalan@Sun.COM 
32087934SMark.Phalan@Sun.COM     *out_len = tot_len;
32097934SMark.Phalan@Sun.COM 
32107934SMark.Phalan@Sun.COM     return 0;
32117934SMark.Phalan@Sun.COM }
32127934SMark.Phalan@Sun.COM #else
32137934SMark.Phalan@Sun.COM /*
32147934SMark.Phalan@Sun.COM  * This is a version that works with a patched Longhorn KDC.
32157934SMark.Phalan@Sun.COM  * (Which should match SP1 ??).
32167934SMark.Phalan@Sun.COM  */
32177934SMark.Phalan@Sun.COM static int
wrap_signeddata(unsigned char * data,unsigned int data_len,unsigned char ** out,unsigned int * out_len,int is_longhorn_server)32187934SMark.Phalan@Sun.COM wrap_signeddata(unsigned char *data, unsigned int data_len,
32197934SMark.Phalan@Sun.COM 	       unsigned char **out, unsigned int *out_len,
32207934SMark.Phalan@Sun.COM 	       int is_longhorn_server)
32217934SMark.Phalan@Sun.COM {
32227934SMark.Phalan@Sun.COM 
32237934SMark.Phalan@Sun.COM     unsigned int oid_len = 0, tot_len = 0, wrap_len = 0, tag_len = 0;
32247934SMark.Phalan@Sun.COM     ASN1_OBJECT *oid = NULL;
32257934SMark.Phalan@Sun.COM     unsigned char *p = NULL;
32267934SMark.Phalan@Sun.COM 
32277934SMark.Phalan@Sun.COM     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
32287934SMark.Phalan@Sun.COM 	     __FUNCTION__, is_longhorn_server);
32297934SMark.Phalan@Sun.COM 
32307934SMark.Phalan@Sun.COM     /* New longhorn is missing another sequence */
32317934SMark.Phalan@Sun.COM     if (is_longhorn_server == 1)
32327934SMark.Phalan@Sun.COM        wrap_len = ASN1_object_size(1, (int)(data_len), V_ASN1_SEQUENCE);
32337934SMark.Phalan@Sun.COM     else
32347934SMark.Phalan@Sun.COM        wrap_len = data_len;
32357934SMark.Phalan@Sun.COM 
32367934SMark.Phalan@Sun.COM     /* Get length to wrap the original data with SEQUENCE tag */
32377934SMark.Phalan@Sun.COM     tag_len = ASN1_object_size(1, (int)wrap_len, V_ASN1_SEQUENCE);
32387934SMark.Phalan@Sun.COM 
32397934SMark.Phalan@Sun.COM     /* Always add oid */
32407934SMark.Phalan@Sun.COM     oid = OBJ_nid2obj(NID_pkcs7_signed);
32417934SMark.Phalan@Sun.COM     oid_len = i2d_ASN1_OBJECT(oid, NULL);
32427934SMark.Phalan@Sun.COM     oid_len += tag_len;
32437934SMark.Phalan@Sun.COM 
32447934SMark.Phalan@Sun.COM     tot_len = ASN1_object_size(1, (int)(oid_len), V_ASN1_SEQUENCE);
32457934SMark.Phalan@Sun.COM 
32467934SMark.Phalan@Sun.COM     p = *out = (unsigned char *)malloc(tot_len);
32477934SMark.Phalan@Sun.COM     if (p == NULL)
32487934SMark.Phalan@Sun.COM        return -1;
32497934SMark.Phalan@Sun.COM 
32507934SMark.Phalan@Sun.COM     ASN1_put_object(&p, 1, (int)(oid_len),
32517934SMark.Phalan@Sun.COM 		    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
32527934SMark.Phalan@Sun.COM 
32537934SMark.Phalan@Sun.COM     i2d_ASN1_OBJECT(oid, &p);
32547934SMark.Phalan@Sun.COM 
32557934SMark.Phalan@Sun.COM     ASN1_put_object(&p, 1, (int)wrap_len, 0, V_ASN1_CONTEXT_SPECIFIC);
32567934SMark.Phalan@Sun.COM 
32577934SMark.Phalan@Sun.COM     /* Wrap in extra seq tag */
32587934SMark.Phalan@Sun.COM     if (is_longhorn_server == 1) {
32597934SMark.Phalan@Sun.COM        ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
32607934SMark.Phalan@Sun.COM     }
32617934SMark.Phalan@Sun.COM     (void) memcpy(p, data, data_len);
32627934SMark.Phalan@Sun.COM 
32637934SMark.Phalan@Sun.COM     *out_len = tot_len;
32647934SMark.Phalan@Sun.COM 
32657934SMark.Phalan@Sun.COM     return 0;
32667934SMark.Phalan@Sun.COM }
32677934SMark.Phalan@Sun.COM 
32687934SMark.Phalan@Sun.COM #endif
32697934SMark.Phalan@Sun.COM #else
32707934SMark.Phalan@Sun.COM static int
wrap_signeddata(unsigned char * data,unsigned int data_len,unsigned char ** out,unsigned int * out_len)32717934SMark.Phalan@Sun.COM wrap_signeddata(unsigned char *data, unsigned int data_len,
32727934SMark.Phalan@Sun.COM 		unsigned char **out, unsigned int *out_len)
32737934SMark.Phalan@Sun.COM {
32747934SMark.Phalan@Sun.COM 
32757934SMark.Phalan@Sun.COM     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
32767934SMark.Phalan@Sun.COM     ASN1_OBJECT *oid = NULL;
32777934SMark.Phalan@Sun.COM     unsigned char *p = NULL;
32787934SMark.Phalan@Sun.COM 
32797934SMark.Phalan@Sun.COM     /* Get length to wrap the original data with SEQUENCE tag */
32807934SMark.Phalan@Sun.COM     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
32817934SMark.Phalan@Sun.COM 
32827934SMark.Phalan@Sun.COM     /* Add the signedData OID and adjust lengths */
32837934SMark.Phalan@Sun.COM     oid = OBJ_nid2obj(NID_pkcs7_signed);
32847934SMark.Phalan@Sun.COM     oid_len = i2d_ASN1_OBJECT(oid, NULL);
32857934SMark.Phalan@Sun.COM 
32867934SMark.Phalan@Sun.COM     tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
32877934SMark.Phalan@Sun.COM 
32887934SMark.Phalan@Sun.COM     p = *out = (unsigned char *)malloc(tot_len);
32897934SMark.Phalan@Sun.COM     if (p == NULL) return -1;
32907934SMark.Phalan@Sun.COM 
32917934SMark.Phalan@Sun.COM     ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
32927934SMark.Phalan@Sun.COM 		    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
32937934SMark.Phalan@Sun.COM 
32947934SMark.Phalan@Sun.COM     i2d_ASN1_OBJECT(oid, &p);
32957934SMark.Phalan@Sun.COM 
32967934SMark.Phalan@Sun.COM     ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
32977934SMark.Phalan@Sun.COM     (void) memcpy(p, data, data_len);
32987934SMark.Phalan@Sun.COM 
32997934SMark.Phalan@Sun.COM     *out_len = tot_len;
33007934SMark.Phalan@Sun.COM 
33017934SMark.Phalan@Sun.COM     return 0;
33027934SMark.Phalan@Sun.COM }
33037934SMark.Phalan@Sun.COM #endif
33047934SMark.Phalan@Sun.COM 
33057934SMark.Phalan@Sun.COM static int
prepare_enc_data(unsigned char * indata,int indata_len,unsigned char ** outdata,int * outdata_len)33067934SMark.Phalan@Sun.COM prepare_enc_data(unsigned char *indata,
33077934SMark.Phalan@Sun.COM 		 int indata_len,
33087934SMark.Phalan@Sun.COM 		 unsigned char **outdata,
33097934SMark.Phalan@Sun.COM 		 int *outdata_len)
33107934SMark.Phalan@Sun.COM {
33117934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
33127934SMark.Phalan@Sun.COM     ASN1_const_CTX c;
33137934SMark.Phalan@Sun.COM     long length = indata_len;
33147934SMark.Phalan@Sun.COM     int Ttag, Tclass;
33157934SMark.Phalan@Sun.COM     long Tlen;
33167934SMark.Phalan@Sun.COM 
33177934SMark.Phalan@Sun.COM     c.pp = (const unsigned char **)&indata;
33187934SMark.Phalan@Sun.COM     c.q = *(const unsigned char **)&indata;
33197934SMark.Phalan@Sun.COM     c.error = ERR_R_NESTED_ASN1_ERROR;
33207934SMark.Phalan@Sun.COM     c.p= *(const unsigned char **)&indata;
33217934SMark.Phalan@Sun.COM     c.max = (length == 0)?0:(c.p+length);
33227934SMark.Phalan@Sun.COM 
33237934SMark.Phalan@Sun.COM     asn1_GetSequence(&c,&length);
33247934SMark.Phalan@Sun.COM 
33257934SMark.Phalan@Sun.COM     ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
33267934SMark.Phalan@Sun.COM     c.p += Tlen;
33277934SMark.Phalan@Sun.COM     ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
33287934SMark.Phalan@Sun.COM 
33297934SMark.Phalan@Sun.COM     asn1_const_Finish(&c);
33307934SMark.Phalan@Sun.COM 
33317934SMark.Phalan@Sun.COM     *outdata = (unsigned char *)malloc((size_t)Tlen);
33327934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
33337934SMark.Phalan@Sun.COM     if (outdata == NULL)
33347934SMark.Phalan@Sun.COM 	return ENOMEM;
33357934SMark.Phalan@Sun.COM 
33367934SMark.Phalan@Sun.COM     (void) memcpy(*outdata, c.p, (size_t)Tlen);
33377934SMark.Phalan@Sun.COM     *outdata_len = Tlen;
33387934SMark.Phalan@Sun.COM 
33397934SMark.Phalan@Sun.COM     return 0;
33407934SMark.Phalan@Sun.COM }
33417934SMark.Phalan@Sun.COM 
33427934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
33437934SMark.Phalan@Sun.COM static void *
pkinit_C_LoadModule(const char * modname,CK_FUNCTION_LIST_PTR_PTR p11p)33447934SMark.Phalan@Sun.COM pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
33457934SMark.Phalan@Sun.COM {
33467934SMark.Phalan@Sun.COM     void *handle;
33477934SMark.Phalan@Sun.COM     CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
33487934SMark.Phalan@Sun.COM 
33497934SMark.Phalan@Sun.COM     pkiDebug("loading module \"%s\"... ", modname);
33507934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
33517934SMark.Phalan@Sun.COM     handle = dlopen(modname, RTLD_NOW | RTLD_GROUP);
33527934SMark.Phalan@Sun.COM     if (handle == NULL) {
33537934SMark.Phalan@Sun.COM 	pkiDebug("not found\n");
33547934SMark.Phalan@Sun.COM 	return NULL;
33557934SMark.Phalan@Sun.COM     }
33567934SMark.Phalan@Sun.COM     getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
33577934SMark.Phalan@Sun.COM     if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
33587934SMark.Phalan@Sun.COM 	(void) dlclose(handle);
33597934SMark.Phalan@Sun.COM 	pkiDebug("failed\n");
33607934SMark.Phalan@Sun.COM 	return NULL;
33617934SMark.Phalan@Sun.COM     }
33627934SMark.Phalan@Sun.COM     pkiDebug("ok\n");
33637934SMark.Phalan@Sun.COM     return handle;
33647934SMark.Phalan@Sun.COM }
33657934SMark.Phalan@Sun.COM 
33667934SMark.Phalan@Sun.COM static CK_RV
pkinit_C_UnloadModule(void * handle)33677934SMark.Phalan@Sun.COM pkinit_C_UnloadModule(void *handle)
33687934SMark.Phalan@Sun.COM {
33697934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
33707934SMark.Phalan@Sun.COM     if (dlclose(handle) != 0)
33717934SMark.Phalan@Sun.COM 	return CKR_GENERAL_ERROR;
33727934SMark.Phalan@Sun.COM 
33737934SMark.Phalan@Sun.COM     return CKR_OK;
33747934SMark.Phalan@Sun.COM }
33757934SMark.Phalan@Sun.COM 
337612941Swill.fiveash@oracle.com /*
3377*12945Swill.fiveash@oracle.com  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3378*12945Swill.fiveash@oracle.com  * code.
3379*12945Swill.fiveash@oracle.com  *
3380*12945Swill.fiveash@oracle.com  * labelstr will be C string containing token label with trailing white space
3381*12945Swill.fiveash@oracle.com  * removed.
3382*12945Swill.fiveash@oracle.com  */
3383*12945Swill.fiveash@oracle.com static void
trim_token_label(CK_TOKEN_INFO * tinfo,char * labelstr,unsigned int labelstr_len)3384*12945Swill.fiveash@oracle.com trim_token_label(CK_TOKEN_INFO *tinfo, char *labelstr, unsigned int labelstr_len)
3385*12945Swill.fiveash@oracle.com {
3386*12945Swill.fiveash@oracle.com     int i;
3387*12945Swill.fiveash@oracle.com 
3388*12945Swill.fiveash@oracle.com     assert(labelstr_len > sizeof (tinfo->label));
3389*12945Swill.fiveash@oracle.com     /*
3390*12945Swill.fiveash@oracle.com      * \0 terminate labelstr in case the last char in the token label is
3391*12945Swill.fiveash@oracle.com      * non-whitespace
3392*12945Swill.fiveash@oracle.com      */
3393*12945Swill.fiveash@oracle.com     labelstr[sizeof (tinfo->label)] = '\0';
3394*12945Swill.fiveash@oracle.com     (void) memcpy(labelstr, (char *) tinfo->label, sizeof (tinfo->label));
3395*12945Swill.fiveash@oracle.com 
3396*12945Swill.fiveash@oracle.com     /* init i so terminating \0 is skipped */
3397*12945Swill.fiveash@oracle.com     for (i = sizeof (tinfo->label) - 1; i >= 0; i--) {
3398*12945Swill.fiveash@oracle.com 	if (labelstr[i] == ' ')
3399*12945Swill.fiveash@oracle.com 	    labelstr[i] = '\0';
3400*12945Swill.fiveash@oracle.com 	else
3401*12945Swill.fiveash@oracle.com 	    break;
3402*12945Swill.fiveash@oracle.com     }
3403*12945Swill.fiveash@oracle.com }
3404*12945Swill.fiveash@oracle.com 
3405*12945Swill.fiveash@oracle.com /*
3406*12945Swill.fiveash@oracle.com  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3407*12945Swill.fiveash@oracle.com  * code.
3408*12945Swill.fiveash@oracle.com  */
3409*12945Swill.fiveash@oracle.com static krb5_error_code
pkinit_prompt_user(krb5_context context,pkinit_identity_crypto_context cctx,krb5_data * reply,char * prompt,int hidden)3410*12945Swill.fiveash@oracle.com pkinit_prompt_user(krb5_context context,
3411*12945Swill.fiveash@oracle.com 		   pkinit_identity_crypto_context cctx,
3412*12945Swill.fiveash@oracle.com 		   krb5_data *reply,
3413*12945Swill.fiveash@oracle.com 		   char *prompt,
3414*12945Swill.fiveash@oracle.com 		   int hidden)
3415*12945Swill.fiveash@oracle.com {
3416*12945Swill.fiveash@oracle.com     krb5_error_code r;
3417*12945Swill.fiveash@oracle.com     krb5_prompt kprompt;
3418*12945Swill.fiveash@oracle.com     krb5_prompt_type prompt_type;
3419*12945Swill.fiveash@oracle.com 
3420*12945Swill.fiveash@oracle.com     if (cctx->prompter == NULL)
3421*12945Swill.fiveash@oracle.com 	return (EINVAL);
3422*12945Swill.fiveash@oracle.com 
3423*12945Swill.fiveash@oracle.com     kprompt.prompt = prompt;
3424*12945Swill.fiveash@oracle.com     kprompt.hidden = hidden;
3425*12945Swill.fiveash@oracle.com     kprompt.reply = reply;
3426*12945Swill.fiveash@oracle.com     /*
3427*12945Swill.fiveash@oracle.com      * Note, assuming this type for now, may need to be passed in in the future.
3428*12945Swill.fiveash@oracle.com      */
3429*12945Swill.fiveash@oracle.com     prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
3430*12945Swill.fiveash@oracle.com 
3431*12945Swill.fiveash@oracle.com     /* PROMPTER_INVOCATION */
3432*12945Swill.fiveash@oracle.com     k5int_set_prompt_types(context, &prompt_type);
3433*12945Swill.fiveash@oracle.com     r = (*cctx->prompter)(context, cctx->prompter_data,
3434*12945Swill.fiveash@oracle.com 			  NULL, NULL, 1, &kprompt);
3435*12945Swill.fiveash@oracle.com     k5int_set_prompt_types(context, NULL);
3436*12945Swill.fiveash@oracle.com     return (r);
3437*12945Swill.fiveash@oracle.com }
3438*12945Swill.fiveash@oracle.com 
3439*12945Swill.fiveash@oracle.com /*
344012941Swill.fiveash@oracle.com  * Solaris Kerberos: this function was changed to support a PIN being passed
344112941Swill.fiveash@oracle.com  * in.  If that is the case the user will not be prompted for their PIN.
344212941Swill.fiveash@oracle.com  */
34437934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_login(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,CK_TOKEN_INFO * tip)34447934SMark.Phalan@Sun.COM pkinit_login(krb5_context context,
34457934SMark.Phalan@Sun.COM 	     pkinit_identity_crypto_context id_cryptoctx,
34467934SMark.Phalan@Sun.COM 	     CK_TOKEN_INFO *tip)
34477934SMark.Phalan@Sun.COM {
34487934SMark.Phalan@Sun.COM     krb5_data rdat;
34497934SMark.Phalan@Sun.COM     char *prompt;
34507934SMark.Phalan@Sun.COM     int prompt_len;
34517934SMark.Phalan@Sun.COM     int r = 0;
34527934SMark.Phalan@Sun.COM 
34537934SMark.Phalan@Sun.COM     if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
34547934SMark.Phalan@Sun.COM 	rdat.data = NULL;
34557934SMark.Phalan@Sun.COM 	rdat.length = 0;
345612941Swill.fiveash@oracle.com     } else if (id_cryptoctx->PIN != NULL) {
345712941Swill.fiveash@oracle.com 	if ((rdat.data = strdup(id_cryptoctx->PIN)) == NULL)
345812941Swill.fiveash@oracle.com 	    return (ENOMEM);
345912941Swill.fiveash@oracle.com 	/*
346012941Swill.fiveash@oracle.com 	 * Don't include NULL string terminator in length calculation as this
346112941Swill.fiveash@oracle.com 	 * PIN is passed to the C_Login function and only the text chars should
346212941Swill.fiveash@oracle.com 	 * be considered to be the PIN.
346312941Swill.fiveash@oracle.com 	 */
346412941Swill.fiveash@oracle.com 	rdat.length = strlen(id_cryptoctx->PIN);
34657934SMark.Phalan@Sun.COM     } else {
3466*12945Swill.fiveash@oracle.com         /* Solaris Kerberos - trim token label */
3467*12945Swill.fiveash@oracle.com 	char tmplabel[sizeof (tip->label) + 1];
346811783SWill.Fiveash@Sun.COM 
346911783SWill.Fiveash@Sun.COM 	if (!id_cryptoctx->prompter) {
347011783SWill.Fiveash@Sun.COM 	    pkiDebug("pkinit_login: id_cryptoctx->prompter is NULL\n");
347111783SWill.Fiveash@Sun.COM 	    /* Solaris Kerberos: Improved error messages */
347211783SWill.Fiveash@Sun.COM 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3473*12945Swill.fiveash@oracle.com 		gettext("Failed to log into token: prompter function is NULL"));
347411783SWill.Fiveash@Sun.COM 	    return (KRB5KDC_ERR_PREAUTH_FAILED);
347511783SWill.Fiveash@Sun.COM 	}
34767934SMark.Phalan@Sun.COM 	/* Solaris Kerberos - Changes for gettext() */
34777934SMark.Phalan@Sun.COM         prompt_len = sizeof (tip->label) + 256;
34787934SMark.Phalan@Sun.COM 	if ((prompt = (char *) malloc(prompt_len)) == NULL)
34797934SMark.Phalan@Sun.COM 	    return ENOMEM;
348011782SWill.Fiveash@Sun.COM 
348111782SWill.Fiveash@Sun.COM 	/* Solaris Kerberos - trim token label which can be padded with space */
3482*12945Swill.fiveash@oracle.com 	trim_token_label(tip, tmplabel, sizeof (tmplabel));
3483*12945Swill.fiveash@oracle.com 	(void) snprintf(prompt, prompt_len, gettext("%s PIN"), tmplabel);
3484*12945Swill.fiveash@oracle.com 
34857934SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
34867934SMark.Phalan@Sun.COM 	if (tip->flags & CKF_USER_PIN_LOCKED)
34877934SMark.Phalan@Sun.COM 	    (void) strlcat(prompt, gettext(" (Warning: PIN locked)"), prompt_len);
34887934SMark.Phalan@Sun.COM 	else if (tip->flags & CKF_USER_PIN_FINAL_TRY)
34897934SMark.Phalan@Sun.COM 	    (void) strlcat(prompt, gettext(" (Warning: PIN final try)"), prompt_len);
34907934SMark.Phalan@Sun.COM 	else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
34917934SMark.Phalan@Sun.COM 	    (void) strlcat(prompt, gettext(" (Warning: PIN count low)"), prompt_len);
349212941Swill.fiveash@oracle.com 	rdat.data = malloc(tip->ulMaxPinLen + 2);
34937934SMark.Phalan@Sun.COM 	rdat.length = tip->ulMaxPinLen + 1;
349412941Swill.fiveash@oracle.com 	/*
349512941Swill.fiveash@oracle.com 	 * Note that the prompter function will set rdat.length such that the
349612941Swill.fiveash@oracle.com 	 * NULL terminator is not included
349712941Swill.fiveash@oracle.com 	 */
34987934SMark.Phalan@Sun.COM 	/* PROMPTER_INVOCATION */
3499*12945Swill.fiveash@oracle.com 	r = pkinit_prompt_user(context, id_cryptoctx, &rdat, prompt, 1);
35007934SMark.Phalan@Sun.COM 	free(prompt);
35017934SMark.Phalan@Sun.COM     }
35027934SMark.Phalan@Sun.COM 
35037934SMark.Phalan@Sun.COM     if (r == 0) {
35047934SMark.Phalan@Sun.COM 	r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
35057934SMark.Phalan@Sun.COM 		(u_char *) rdat.data, rdat.length);
35067934SMark.Phalan@Sun.COM 
35077934SMark.Phalan@Sun.COM 	if (r != CKR_OK) {
35087934SMark.Phalan@Sun.COM 	    pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r));
35097934SMark.Phalan@Sun.COM 	    /* Solaris Kerberos: Improved error messages */
35107934SMark.Phalan@Sun.COM 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3511*12945Swill.fiveash@oracle.com 		gettext("Failed to log into token: %s"),
35127934SMark.Phalan@Sun.COM 		pkinit_pkcs11_code_to_text(r));
35137934SMark.Phalan@Sun.COM 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
351411781SWill.Fiveash@Sun.COM 	} else {
351511781SWill.Fiveash@Sun.COM 	    /* Solaris Kerberos: only need to login once */
351611781SWill.Fiveash@Sun.COM             id_cryptoctx->p11flags |= C_LOGIN_DONE;
351711781SWill.Fiveash@Sun.COM         }
35187934SMark.Phalan@Sun.COM     }
351912941Swill.fiveash@oracle.com     if (rdat.data) {
352012941Swill.fiveash@oracle.com 	(void) memset(rdat.data, 0, rdat.length);
35217934SMark.Phalan@Sun.COM 	free(rdat.data);
352212941Swill.fiveash@oracle.com     }
35237934SMark.Phalan@Sun.COM 
3524*12945Swill.fiveash@oracle.com     return (r);
3525*12945Swill.fiveash@oracle.com }
3526*12945Swill.fiveash@oracle.com 
3527*12945Swill.fiveash@oracle.com /*
3528*12945Swill.fiveash@oracle.com  * Solaris Kerberos: added these structs in support of prompting user for
3529*12945Swill.fiveash@oracle.com  * missing token.
3530*12945Swill.fiveash@oracle.com  */
3531*12945Swill.fiveash@oracle.com struct _token_entry {
3532*12945Swill.fiveash@oracle.com     CK_SLOT_ID slotID;
3533*12945Swill.fiveash@oracle.com     CK_SESSION_HANDLE session;
3534*12945Swill.fiveash@oracle.com     CK_TOKEN_INFO token_info;
3535*12945Swill.fiveash@oracle.com };
3536*12945Swill.fiveash@oracle.com struct _token_choices {
3537*12945Swill.fiveash@oracle.com     unsigned int numtokens;
3538*12945Swill.fiveash@oracle.com     struct _token_entry *token_array;
3539*12945Swill.fiveash@oracle.com };
3540*12945Swill.fiveash@oracle.com 
3541*12945Swill.fiveash@oracle.com 
3542*12945Swill.fiveash@oracle.com /*
3543*12945Swill.fiveash@oracle.com  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3544*12945Swill.fiveash@oracle.com  * code.
3545*12945Swill.fiveash@oracle.com  */
3546*12945Swill.fiveash@oracle.com static krb5_error_code
pkinit_prompt_token(krb5_context context,pkinit_identity_crypto_context cctx)3547*12945Swill.fiveash@oracle.com pkinit_prompt_token(krb5_context context,
3548*12945Swill.fiveash@oracle.com 		    pkinit_identity_crypto_context cctx)
3549*12945Swill.fiveash@oracle.com {
3550*12945Swill.fiveash@oracle.com     char tmpbuf[4];
3551*12945Swill.fiveash@oracle.com     krb5_data reply;
3552*12945Swill.fiveash@oracle.com     char *token_prompt = gettext("If you have a smartcard insert it now. "
3553*12945Swill.fiveash@oracle.com 				 "Press enter to continue");
3554*12945Swill.fiveash@oracle.com 
3555*12945Swill.fiveash@oracle.com     reply.data = tmpbuf;
3556*12945Swill.fiveash@oracle.com     reply.length = sizeof(tmpbuf);
3557*12945Swill.fiveash@oracle.com 
3558*12945Swill.fiveash@oracle.com     /* note, don't care about the reply */
3559*12945Swill.fiveash@oracle.com     return (pkinit_prompt_user(context, cctx, &reply, token_prompt, 0));
3560*12945Swill.fiveash@oracle.com }
3561*12945Swill.fiveash@oracle.com 
3562*12945Swill.fiveash@oracle.com /*
3563*12945Swill.fiveash@oracle.com  * Solaris Kerberos: new defines for prompting support.
3564*12945Swill.fiveash@oracle.com  */
3565*12945Swill.fiveash@oracle.com #define CHOOSE_THIS_TOKEN 0
3566*12945Swill.fiveash@oracle.com #define CHOOSE_RESCAN 1
3567*12945Swill.fiveash@oracle.com #define CHOOSE_SKIP 2
3568*12945Swill.fiveash@oracle.com #define CHOOSE_SEE_NEXT 3
3569*12945Swill.fiveash@oracle.com 
3570*12945Swill.fiveash@oracle.com #define RESCAN_TOKENS -1
3571*12945Swill.fiveash@oracle.com #define SKIP_TOKENS -2
3572*12945Swill.fiveash@oracle.com 
3573*12945Swill.fiveash@oracle.com /*
3574*12945Swill.fiveash@oracle.com  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3575*12945Swill.fiveash@oracle.com  * code.
3576*12945Swill.fiveash@oracle.com  *
3577*12945Swill.fiveash@oracle.com  * This prompts to user for various choices regarding a token to use.  Note
3578*12945Swill.fiveash@oracle.com  * that if there is no error, choice will be set to one of:
3579*12945Swill.fiveash@oracle.com  * - the token_choices->token_array entry
3580*12945Swill.fiveash@oracle.com  * - RESCAN_TOKENS
3581*12945Swill.fiveash@oracle.com  * - SKIP_TOKENS
3582*12945Swill.fiveash@oracle.com  */
3583*12945Swill.fiveash@oracle.com static int
pkinit_choose_tokens(krb5_context context,pkinit_identity_crypto_context cctx,struct _token_choices * token_choices,int * choice)3584*12945Swill.fiveash@oracle.com pkinit_choose_tokens(krb5_context context,
3585*12945Swill.fiveash@oracle.com 		     pkinit_identity_crypto_context cctx,
3586*12945Swill.fiveash@oracle.com 		     struct _token_choices *token_choices,
3587*12945Swill.fiveash@oracle.com 		     int *choice)
3588*12945Swill.fiveash@oracle.com {
3589*12945Swill.fiveash@oracle.com     krb5_error_code r;
3590*12945Swill.fiveash@oracle.com     /*
3591*12945Swill.fiveash@oracle.com      * Assuming that PAM_MAX_MSG_SIZE is a reasonable restriction. Note that -
3592*12945Swill.fiveash@oracle.com      * 2 is to account for the fact that a krb prompter to PAM conv bridge will
3593*12945Swill.fiveash@oracle.com      * add ": ".
3594*12945Swill.fiveash@oracle.com      */
3595*12945Swill.fiveash@oracle.com     char prompt[PAM_MAX_MSG_SIZE - 2];
3596*12945Swill.fiveash@oracle.com     char tmpbuf[4];
3597*12945Swill.fiveash@oracle.com     char tmplabel[sizeof (token_choices->token_array->token_info.label) + 1];
3598*12945Swill.fiveash@oracle.com     krb5_data reply;
3599*12945Swill.fiveash@oracle.com     int i, num_used, tmpchoice;
3600*12945Swill.fiveash@oracle.com 
3601*12945Swill.fiveash@oracle.com     assert(token_choices != NULL);
3602*12945Swill.fiveash@oracle.com     assert(choice != NULL);
3603*12945Swill.fiveash@oracle.com 
3604*12945Swill.fiveash@oracle.com     /* Create the menu prompt */
3605*12945Swill.fiveash@oracle.com 
3606*12945Swill.fiveash@oracle.com     /* only need to do this once before the for loop */
3607*12945Swill.fiveash@oracle.com     reply.data = tmpbuf;
3608*12945Swill.fiveash@oracle.com 
3609*12945Swill.fiveash@oracle.com     for (i = 0; i < token_choices->numtokens; i++) {
3610*12945Swill.fiveash@oracle.com 
3611*12945Swill.fiveash@oracle.com 	trim_token_label(&token_choices->token_array[i].token_info, tmplabel,
3612*12945Swill.fiveash@oracle.com 			 sizeof (tmplabel));
3613*12945Swill.fiveash@oracle.com 
3614*12945Swill.fiveash@oracle.com 	if (i == (token_choices->numtokens - 1)) {
3615*12945Swill.fiveash@oracle.com 	    /* no more smartcards/tokens */
3616*12945Swill.fiveash@oracle.com 	    if ((num_used = snprintf(prompt, sizeof (prompt),
3617*12945Swill.fiveash@oracle.com 				     "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n",
3618*12945Swill.fiveash@oracle.com 				     /*
3619*12945Swill.fiveash@oracle.com 				      * TRANSLATION_NOTE: Translations of the
3620*12945Swill.fiveash@oracle.com 				      * following 5 strings must not exceed 450
3621*12945Swill.fiveash@oracle.com 				      * bytes total.
3622*12945Swill.fiveash@oracle.com 				      */
3623*12945Swill.fiveash@oracle.com 				     gettext("Select one of the following and press enter:"),
3624*12945Swill.fiveash@oracle.com 				     CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3625*12945Swill.fiveash@oracle.com                                      gettext("in slot"), token_choices->token_array[i].slotID,
3626*12945Swill.fiveash@oracle.com 				     CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3627*12945Swill.fiveash@oracle.com 				     CHOOSE_SKIP, gettext("Skip smartcard authentication")))
3628*12945Swill.fiveash@oracle.com 		>= sizeof (prompt)) {
3629*12945Swill.fiveash@oracle.com 		pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3630*12945Swill.fiveash@oracle.com 			 " sizeof prompt: %d\n", num_used, sizeof (prompt));
3631*12945Swill.fiveash@oracle.com 		krb5_set_error_message(context, EINVAL,
3632*12945Swill.fiveash@oracle.com                                gettext("In pkinit_choose_tokens: prompt size"
3633*12945Swill.fiveash@oracle.com 				      " %d exceeds prompt buffer size %d"),
3634*12945Swill.fiveash@oracle.com 			       num_used, sizeof(prompt));
3635*12945Swill.fiveash@oracle.com 		(void) snprintf(prompt, sizeof (prompt), "%s",
3636*12945Swill.fiveash@oracle.com 			        gettext("Error: PKINIT prompt message is too large for buffer, "
3637*12945Swill.fiveash@oracle.com 					"please alert the system administrator. Press enter to "
3638*12945Swill.fiveash@oracle.com 					"continue"));
3639*12945Swill.fiveash@oracle.com 		reply.length = sizeof(tmpbuf);
3640*12945Swill.fiveash@oracle.com 		if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3641*12945Swill.fiveash@oracle.com 		    return (r);
3642*12945Swill.fiveash@oracle.com 		return (EINVAL);
3643*12945Swill.fiveash@oracle.com 	    }
3644*12945Swill.fiveash@oracle.com 	} else {
3645*12945Swill.fiveash@oracle.com 	    if ((num_used = snprintf(prompt, sizeof (prompt),
3646*12945Swill.fiveash@oracle.com 				     "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n%d: %s\n",
3647*12945Swill.fiveash@oracle.com 				     /*
3648*12945Swill.fiveash@oracle.com 				      * TRANSLATION_NOTE: Translations of the
3649*12945Swill.fiveash@oracle.com 				      * following 6 strings must not exceed 445
3650*12945Swill.fiveash@oracle.com 				      * bytes total.
3651*12945Swill.fiveash@oracle.com 				      */
3652*12945Swill.fiveash@oracle.com 				     gettext("Select one of the following and press enter:"),
3653*12945Swill.fiveash@oracle.com 				     CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3654*12945Swill.fiveash@oracle.com                                      gettext("in slot"), token_choices->token_array[i].slotID,
3655*12945Swill.fiveash@oracle.com 				     CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3656*12945Swill.fiveash@oracle.com 				     CHOOSE_SKIP, gettext("Skip smartcard authentication"),
3657*12945Swill.fiveash@oracle.com 				     CHOOSE_SEE_NEXT, gettext("See next smartcard")))
3658*12945Swill.fiveash@oracle.com 		>= sizeof (prompt)) {
3659*12945Swill.fiveash@oracle.com 
3660*12945Swill.fiveash@oracle.com 		pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3661*12945Swill.fiveash@oracle.com 			 " sizeof prompt: %d\n", num_used, sizeof (prompt));
3662*12945Swill.fiveash@oracle.com 		krb5_set_error_message(context, EINVAL,
3663*12945Swill.fiveash@oracle.com 				       gettext("In pkinit_choose_tokens: prompt size"
3664*12945Swill.fiveash@oracle.com 					       " %d exceeds prompt buffer size %d"),
3665*12945Swill.fiveash@oracle.com 				       num_used, sizeof(prompt));
3666*12945Swill.fiveash@oracle.com 		(void) snprintf(prompt, sizeof (prompt), "%s",
3667*12945Swill.fiveash@oracle.com 				gettext("Error: PKINIT prompt message is too large for buffer, "
3668*12945Swill.fiveash@oracle.com 					"please alert the system administrator. Press enter to "
3669*12945Swill.fiveash@oracle.com 					"continue"));
3670*12945Swill.fiveash@oracle.com 		reply.length = sizeof(tmpbuf);
3671*12945Swill.fiveash@oracle.com 		if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3672*12945Swill.fiveash@oracle.com 		    return (r);
3673*12945Swill.fiveash@oracle.com 		return (EINVAL);
3674*12945Swill.fiveash@oracle.com 	    }
3675*12945Swill.fiveash@oracle.com 	}
3676*12945Swill.fiveash@oracle.com 
3677*12945Swill.fiveash@oracle.com         /*
3678*12945Swill.fiveash@oracle.com 	 * reply.length needs to be reset to length of tmpbuf before calling
3679*12945Swill.fiveash@oracle.com 	 * prompter
3680*12945Swill.fiveash@oracle.com          */
3681*12945Swill.fiveash@oracle.com         reply.length = sizeof(tmpbuf);
3682*12945Swill.fiveash@oracle.com 	if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3683*12945Swill.fiveash@oracle.com 	    return (r);
3684*12945Swill.fiveash@oracle.com 
3685*12945Swill.fiveash@oracle.com 	if (reply.length == 0) {
3686*12945Swill.fiveash@oracle.com 	    return (EINVAL);
3687*12945Swill.fiveash@oracle.com 	} else {
3688*12945Swill.fiveash@oracle.com             char *cp = reply.data;
3689*12945Swill.fiveash@oracle.com             /* reply better be digits */
3690*12945Swill.fiveash@oracle.com             while (*cp != NULL) {
3691*12945Swill.fiveash@oracle.com                 if (!isdigit(*cp++))
3692*12945Swill.fiveash@oracle.com                     return (EINVAL);
3693*12945Swill.fiveash@oracle.com             }
3694*12945Swill.fiveash@oracle.com 	    errno = 0;
3695*12945Swill.fiveash@oracle.com 	    tmpchoice = (int) strtol(reply.data, (char **)NULL, 10);
3696*12945Swill.fiveash@oracle.com 	    if (errno != 0)
3697*12945Swill.fiveash@oracle.com 		return (errno);
3698*12945Swill.fiveash@oracle.com 	}
3699*12945Swill.fiveash@oracle.com 
3700*12945Swill.fiveash@oracle.com 	switch (tmpchoice) {
3701*12945Swill.fiveash@oracle.com 	case CHOOSE_THIS_TOKEN:
3702*12945Swill.fiveash@oracle.com 	    *choice = i; /* chosen entry of token_choices->token_array */
3703*12945Swill.fiveash@oracle.com 	    return (0);
3704*12945Swill.fiveash@oracle.com 	case CHOOSE_RESCAN:
3705*12945Swill.fiveash@oracle.com 	    *choice = RESCAN_TOKENS; /* rescan for new smartcard */
3706*12945Swill.fiveash@oracle.com 	    return (0);
3707*12945Swill.fiveash@oracle.com 	case CHOOSE_SKIP:
3708*12945Swill.fiveash@oracle.com 	    *choice = SKIP_TOKENS; /* skip smartcard auth */
3709*12945Swill.fiveash@oracle.com 	    return (0);
3710*12945Swill.fiveash@oracle.com 	case CHOOSE_SEE_NEXT: /* see next smartcard */
3711*12945Swill.fiveash@oracle.com 	    continue;
3712*12945Swill.fiveash@oracle.com 	default:
3713*12945Swill.fiveash@oracle.com 	    return (EINVAL);
3714*12945Swill.fiveash@oracle.com 	}
3715*12945Swill.fiveash@oracle.com     }
3716*12945Swill.fiveash@oracle.com 
3717*12945Swill.fiveash@oracle.com     return (0);
37187934SMark.Phalan@Sun.COM }
37197934SMark.Phalan@Sun.COM 
3720*12945Swill.fiveash@oracle.com /*
3721*12945Swill.fiveash@oracle.com  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3722*12945Swill.fiveash@oracle.com  * code.
3723*12945Swill.fiveash@oracle.com  *
3724*12945Swill.fiveash@oracle.com  * Note, this isn't the best solution to providing a function to check the
3725*12945Swill.fiveash@oracle.com  * certs in a token however I wanted to avoid rewriting a bunch of code so I
3726*12945Swill.fiveash@oracle.com  * settled for some duplication of processing.
3727*12945Swill.fiveash@oracle.com  */
3728*12945Swill.fiveash@oracle.com static krb5_error_code
check_load_certs(krb5_context context,CK_SESSION_HANDLE session,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ,int do_matching,int load_cert)3729*12945Swill.fiveash@oracle.com check_load_certs(krb5_context context,
3730*12945Swill.fiveash@oracle.com             CK_SESSION_HANDLE session,
3731*12945Swill.fiveash@oracle.com 	    pkinit_plg_crypto_context plg_cryptoctx,
3732*12945Swill.fiveash@oracle.com 	    pkinit_req_crypto_context req_cryptoctx,
3733*12945Swill.fiveash@oracle.com             pkinit_identity_crypto_context id_cryptoctx,
3734*12945Swill.fiveash@oracle.com             krb5_principal princ,
3735*12945Swill.fiveash@oracle.com             int do_matching,
3736*12945Swill.fiveash@oracle.com             int load_cert)
3737*12945Swill.fiveash@oracle.com {
3738*12945Swill.fiveash@oracle.com     CK_OBJECT_CLASS cls;
3739*12945Swill.fiveash@oracle.com     CK_OBJECT_HANDLE obj;
3740*12945Swill.fiveash@oracle.com     CK_ATTRIBUTE attrs[4];
3741*12945Swill.fiveash@oracle.com     CK_ULONG count;
3742*12945Swill.fiveash@oracle.com     CK_CERTIFICATE_TYPE certtype;
3743*12945Swill.fiveash@oracle.com     CK_BYTE_PTR cert = NULL, cert_id = NULL;
3744*12945Swill.fiveash@oracle.com     const unsigned char *cp;
3745*12945Swill.fiveash@oracle.com     int i, r;
3746*12945Swill.fiveash@oracle.com     unsigned int nattrs;
3747*12945Swill.fiveash@oracle.com     X509 *x = NULL;
3748*12945Swill.fiveash@oracle.com 
3749*12945Swill.fiveash@oracle.com     cls = CKO_CERTIFICATE;
3750*12945Swill.fiveash@oracle.com     attrs[0].type = CKA_CLASS;
3751*12945Swill.fiveash@oracle.com     attrs[0].pValue = &cls;
3752*12945Swill.fiveash@oracle.com     attrs[0].ulValueLen = sizeof cls;
3753*12945Swill.fiveash@oracle.com 
3754*12945Swill.fiveash@oracle.com     certtype = CKC_X_509;
3755*12945Swill.fiveash@oracle.com     attrs[1].type = CKA_CERTIFICATE_TYPE;
3756*12945Swill.fiveash@oracle.com     attrs[1].pValue = &certtype;
3757*12945Swill.fiveash@oracle.com     attrs[1].ulValueLen = sizeof certtype;
3758*12945Swill.fiveash@oracle.com 
3759*12945Swill.fiveash@oracle.com     nattrs = 2;
3760*12945Swill.fiveash@oracle.com 
3761*12945Swill.fiveash@oracle.com     /* If a cert id and/or label were given, use them too */
3762*12945Swill.fiveash@oracle.com     if (id_cryptoctx->cert_id_len > 0) {
3763*12945Swill.fiveash@oracle.com 	attrs[nattrs].type = CKA_ID;
3764*12945Swill.fiveash@oracle.com 	attrs[nattrs].pValue = id_cryptoctx->cert_id;
3765*12945Swill.fiveash@oracle.com 	attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
3766*12945Swill.fiveash@oracle.com 	nattrs++;
3767*12945Swill.fiveash@oracle.com     }
3768*12945Swill.fiveash@oracle.com     if (id_cryptoctx->cert_label != NULL) {
3769*12945Swill.fiveash@oracle.com 	attrs[nattrs].type = CKA_LABEL;
3770*12945Swill.fiveash@oracle.com 	attrs[nattrs].pValue = id_cryptoctx->cert_label;
3771*12945Swill.fiveash@oracle.com 	attrs[nattrs].ulValueLen = strlen(id_cryptoctx->cert_label);
3772*12945Swill.fiveash@oracle.com 	nattrs++;
3773*12945Swill.fiveash@oracle.com     }
3774*12945Swill.fiveash@oracle.com 
3775*12945Swill.fiveash@oracle.com     r = id_cryptoctx->p11->C_FindObjectsInit(session, attrs, nattrs);
3776*12945Swill.fiveash@oracle.com     if (r != CKR_OK) {
3777*12945Swill.fiveash@oracle.com         pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r));
3778*12945Swill.fiveash@oracle.com         krb5_set_error_message(context, EINVAL,
3779*12945Swill.fiveash@oracle.com                                gettext("PKCS11 error from C_FindObjectsInit: %s"),
3780*12945Swill.fiveash@oracle.com                                pkinit_pkcs11_code_to_text(r));
3781*12945Swill.fiveash@oracle.com         r = EINVAL;
3782*12945Swill.fiveash@oracle.com         goto out;
3783*12945Swill.fiveash@oracle.com     }
3784*12945Swill.fiveash@oracle.com 
3785*12945Swill.fiveash@oracle.com     for (i = 0; ; i++) {
3786*12945Swill.fiveash@oracle.com 	if (i >= MAX_CREDS_ALLOWED) {
3787*12945Swill.fiveash@oracle.com             r = EINVAL;
3788*12945Swill.fiveash@oracle.com             goto out;
3789*12945Swill.fiveash@oracle.com         }
3790*12945Swill.fiveash@oracle.com 
3791*12945Swill.fiveash@oracle.com 	/* Look for x.509 cert */
3792*12945Swill.fiveash@oracle.com 	/* Solaris Kerberos */
3793*12945Swill.fiveash@oracle.com 	if ((r = id_cryptoctx->p11->C_FindObjects(session, &obj, 1, &count))
3794*12945Swill.fiveash@oracle.com             != CKR_OK || count == 0) {
3795*12945Swill.fiveash@oracle.com 	    id_cryptoctx->creds[i] = NULL;
3796*12945Swill.fiveash@oracle.com 	    break;
3797*12945Swill.fiveash@oracle.com 	}
3798*12945Swill.fiveash@oracle.com 
3799*12945Swill.fiveash@oracle.com 	/* Get cert and id len */
3800*12945Swill.fiveash@oracle.com 	attrs[0].type = CKA_VALUE;
3801*12945Swill.fiveash@oracle.com 	attrs[0].pValue = NULL;
3802*12945Swill.fiveash@oracle.com 	attrs[0].ulValueLen = 0;
3803*12945Swill.fiveash@oracle.com 
3804*12945Swill.fiveash@oracle.com 	attrs[1].type = CKA_ID;
3805*12945Swill.fiveash@oracle.com 	attrs[1].pValue = NULL;
3806*12945Swill.fiveash@oracle.com 	attrs[1].ulValueLen = 0;
3807*12945Swill.fiveash@oracle.com 
3808*12945Swill.fiveash@oracle.com 	if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
3809*12945Swill.fiveash@oracle.com                                                         obj,
3810*12945Swill.fiveash@oracle.com                                                         attrs,
3811*12945Swill.fiveash@oracle.com                                                         2)) != CKR_OK &&
3812*12945Swill.fiveash@oracle.com             r != CKR_BUFFER_TOO_SMALL) {
3813*12945Swill.fiveash@oracle.com             pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
3814*12945Swill.fiveash@oracle.com 	    krb5_set_error_message(context, EINVAL,
3815*12945Swill.fiveash@oracle.com 				   gettext("Error from PKCS11 C_GetAttributeValue: %s"),
3816*12945Swill.fiveash@oracle.com 				   pkinit_pkcs11_code_to_text(r));
3817*12945Swill.fiveash@oracle.com             r = EINVAL;
3818*12945Swill.fiveash@oracle.com             goto out;
3819*12945Swill.fiveash@oracle.com         }
3820*12945Swill.fiveash@oracle.com 	cert = malloc((size_t) attrs[0].ulValueLen + 1);
3821*12945Swill.fiveash@oracle.com 	if (cert == NULL) {
3822*12945Swill.fiveash@oracle.com 	    r = ENOMEM;
3823*12945Swill.fiveash@oracle.com             goto out;
3824*12945Swill.fiveash@oracle.com         }
3825*12945Swill.fiveash@oracle.com 	cert_id = malloc((size_t) attrs[1].ulValueLen + 1);
3826*12945Swill.fiveash@oracle.com 	if (cert_id == NULL) {
3827*12945Swill.fiveash@oracle.com 	    r = ENOMEM;
3828*12945Swill.fiveash@oracle.com             goto out;
3829*12945Swill.fiveash@oracle.com         }
3830*12945Swill.fiveash@oracle.com 
3831*12945Swill.fiveash@oracle.com 	/* Read the cert and id off the card */
3832*12945Swill.fiveash@oracle.com 
3833*12945Swill.fiveash@oracle.com 	attrs[0].type = CKA_VALUE;
3834*12945Swill.fiveash@oracle.com 	attrs[0].pValue = cert;
3835*12945Swill.fiveash@oracle.com 
3836*12945Swill.fiveash@oracle.com 	attrs[1].type = CKA_ID;
3837*12945Swill.fiveash@oracle.com 	attrs[1].pValue = cert_id;
3838*12945Swill.fiveash@oracle.com 
3839*12945Swill.fiveash@oracle.com 	if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
3840*12945Swill.fiveash@oracle.com 		obj, attrs, 2)) != CKR_OK) {
3841*12945Swill.fiveash@oracle.com 	    pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
3842*12945Swill.fiveash@oracle.com 	    krb5_set_error_message(context, EINVAL,
3843*12945Swill.fiveash@oracle.com 				   gettext("Error from PKCS11 C_GetAttributeValue: %s"),
3844*12945Swill.fiveash@oracle.com 				   pkinit_pkcs11_code_to_text(r));
3845*12945Swill.fiveash@oracle.com 	    r = EINVAL;
3846*12945Swill.fiveash@oracle.com             goto out;
3847*12945Swill.fiveash@oracle.com 	}
3848*12945Swill.fiveash@oracle.com 
3849*12945Swill.fiveash@oracle.com 	pkiDebug("cert %d size %d id %d idlen %d\n", i,
3850*12945Swill.fiveash@oracle.com 	    (int) attrs[0].ulValueLen, (int) cert_id[0],
3851*12945Swill.fiveash@oracle.com 	    (int) attrs[1].ulValueLen);
3852*12945Swill.fiveash@oracle.com 
3853*12945Swill.fiveash@oracle.com 	cp = (unsigned char *) cert;
3854*12945Swill.fiveash@oracle.com 	x = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
3855*12945Swill.fiveash@oracle.com 	if (x == NULL) {
3856*12945Swill.fiveash@oracle.com 	    r = EINVAL;
3857*12945Swill.fiveash@oracle.com             goto out;
3858*12945Swill.fiveash@oracle.com         }
3859*12945Swill.fiveash@oracle.com 
3860*12945Swill.fiveash@oracle.com 	id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
3861*12945Swill.fiveash@oracle.com 	if (id_cryptoctx->creds[i] == NULL) {
3862*12945Swill.fiveash@oracle.com 	    r = ENOMEM;
3863*12945Swill.fiveash@oracle.com             goto out;
3864*12945Swill.fiveash@oracle.com         }
3865*12945Swill.fiveash@oracle.com 	id_cryptoctx->creds[i]->cert = x;
3866*12945Swill.fiveash@oracle.com 	id_cryptoctx->creds[i]->key = NULL;
3867*12945Swill.fiveash@oracle.com 	id_cryptoctx->creds[i]->cert_id = cert_id;
3868*12945Swill.fiveash@oracle.com         cert_id = NULL;
3869*12945Swill.fiveash@oracle.com 	id_cryptoctx->creds[i]->cert_id_len = attrs[1].ulValueLen;
3870*12945Swill.fiveash@oracle.com 	free(cert);
3871*12945Swill.fiveash@oracle.com         cert = NULL;
3872*12945Swill.fiveash@oracle.com     }
3873*12945Swill.fiveash@oracle.com     id_cryptoctx->p11->C_FindObjectsFinal(session);
3874*12945Swill.fiveash@oracle.com 
3875*12945Swill.fiveash@oracle.com     if (id_cryptoctx->creds[0] == NULL || id_cryptoctx->creds[0]->cert == NULL) {
3876*12945Swill.fiveash@oracle.com 	r = ENOENT;
3877*12945Swill.fiveash@oracle.com     } else if (do_matching){
3878*12945Swill.fiveash@oracle.com         /*
3879*12945Swill.fiveash@oracle.com          * Do not let pkinit_cert_matching set the primary cert in id_cryptoctx
3880*12945Swill.fiveash@oracle.com          * as this will be done later.
3881*12945Swill.fiveash@oracle.com          */
3882*12945Swill.fiveash@oracle.com         r = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
3883*12945Swill.fiveash@oracle.com                                  id_cryptoctx, princ, FALSE);
3884*12945Swill.fiveash@oracle.com     }
3885*12945Swill.fiveash@oracle.com 
3886*12945Swill.fiveash@oracle.com out:
3887*12945Swill.fiveash@oracle.com     if ((r != 0 || !load_cert) &&
3888*12945Swill.fiveash@oracle.com         id_cryptoctx->creds[0] != NULL &&
3889*12945Swill.fiveash@oracle.com         id_cryptoctx->creds[0]->cert != NULL) {
3890*12945Swill.fiveash@oracle.com         /*
3891*12945Swill.fiveash@oracle.com          * If there's an error or load_cert isn't 1 free all the certs loaded
3892*12945Swill.fiveash@oracle.com          * onto id_cryptoctx.
3893*12945Swill.fiveash@oracle.com          */
3894*12945Swill.fiveash@oracle.com         (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
3895*12945Swill.fiveash@oracle.com                                      id_cryptoctx);
3896*12945Swill.fiveash@oracle.com     }
3897*12945Swill.fiveash@oracle.com 
3898*12945Swill.fiveash@oracle.com     if (cert)
3899*12945Swill.fiveash@oracle.com         free(cert);
3900*12945Swill.fiveash@oracle.com 
3901*12945Swill.fiveash@oracle.com     if (cert_id)
3902*12945Swill.fiveash@oracle.com         free(cert_id);
3903*12945Swill.fiveash@oracle.com 
3904*12945Swill.fiveash@oracle.com     return (r);
3905*12945Swill.fiveash@oracle.com }
3906*12945Swill.fiveash@oracle.com 
3907*12945Swill.fiveash@oracle.com /*
3908*12945Swill.fiveash@oracle.com  * Solaris Kerberos: this function has been significantly modified to prompt
3909*12945Swill.fiveash@oracle.com  * the user in certain cases so defer to this version when resyncing MIT code.
3910*12945Swill.fiveash@oracle.com  *
3911*12945Swill.fiveash@oracle.com  * pkinit_open_session now does several things including prompting the user if
3912*12945Swill.fiveash@oracle.com  * do_matching is set which indicates the code is executing in a client
3913*12945Swill.fiveash@oracle.com  * context.  This function fills out a pkinit_identity_crypto_context with a
3914*12945Swill.fiveash@oracle.com  * set of certs and a open session if a token can be found that matches all
3915*12945Swill.fiveash@oracle.com  * supplied criteria.  If no token is found then the user is prompted one time
3916*12945Swill.fiveash@oracle.com  * to insert their token.  If there is more than one token that matches all
3917*12945Swill.fiveash@oracle.com  * client criteria the user is prompted to make a choice if in client context.
3918*12945Swill.fiveash@oracle.com  * If do_matching is false (KDC context) then the first token matching all
3919*12945Swill.fiveash@oracle.com  * server criteria is chosen.
3920*12945Swill.fiveash@oracle.com  */
39217934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_open_session(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context cctx,krb5_principal princ,int do_matching)39227934SMark.Phalan@Sun.COM pkinit_open_session(krb5_context context,
3923*12945Swill.fiveash@oracle.com                     pkinit_plg_crypto_context plg_cryptoctx,
3924*12945Swill.fiveash@oracle.com                     pkinit_req_crypto_context req_cryptoctx,
3925*12945Swill.fiveash@oracle.com                     pkinit_identity_crypto_context cctx,
3926*12945Swill.fiveash@oracle.com                     krb5_principal princ,
3927*12945Swill.fiveash@oracle.com                     int do_matching)
39287934SMark.Phalan@Sun.COM {
39297934SMark.Phalan@Sun.COM     int i, r;
39307934SMark.Phalan@Sun.COM     CK_ULONG count = 0;
3931*12945Swill.fiveash@oracle.com     CK_SLOT_ID_PTR slotlist = NULL, tmpslotlist = NULL;
39327934SMark.Phalan@Sun.COM     CK_TOKEN_INFO tinfo;
3933*12945Swill.fiveash@oracle.com     krb5_boolean tokenmatch = FALSE;
3934*12945Swill.fiveash@oracle.com     CK_SESSION_HANDLE tmpsession = NULL;
3935*12945Swill.fiveash@oracle.com     struct _token_choices token_choices;
3936*12945Swill.fiveash@oracle.com     int choice = 0;
3937*12945Swill.fiveash@oracle.com 
3938*12945Swill.fiveash@oracle.com     if (cctx->session != CK_INVALID_HANDLE)
39397934SMark.Phalan@Sun.COM 	return 0; /* session already open */
39407934SMark.Phalan@Sun.COM 
39417934SMark.Phalan@Sun.COM     /* Load module */
3942*12945Swill.fiveash@oracle.com     if (cctx->p11_module == NULL) {
3943*12945Swill.fiveash@oracle.com         cctx->p11_module =
3944*12945Swill.fiveash@oracle.com             pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11);
3945*12945Swill.fiveash@oracle.com         if (cctx->p11_module == NULL)
3946*12945Swill.fiveash@oracle.com             return KRB5KDC_ERR_PREAUTH_FAILED;
3947*12945Swill.fiveash@oracle.com     }
39487934SMark.Phalan@Sun.COM 
39497934SMark.Phalan@Sun.COM     /* Init */
39507934SMark.Phalan@Sun.COM     /* Solaris Kerberos: Don't fail if cryptoki is already initialized */
39517934SMark.Phalan@Sun.COM     r = cctx->p11->C_Initialize(NULL);
39527934SMark.Phalan@Sun.COM     if (r != CKR_OK && r != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
39537934SMark.Phalan@Sun.COM 	pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r));
3954*12945Swill.fiveash@oracle.com 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3955*12945Swill.fiveash@oracle.com 			       gettext("Error from PKCS11 C_Initialize: %s"),
3956*12945Swill.fiveash@oracle.com 			       pkinit_pkcs11_code_to_text(r));
39577934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
39587934SMark.Phalan@Sun.COM     }
39597934SMark.Phalan@Sun.COM 
3960*12945Swill.fiveash@oracle.com     (void) memset(&token_choices, 0, sizeof(token_choices));
3961*12945Swill.fiveash@oracle.com 
39627934SMark.Phalan@Sun.COM     /*
39637934SMark.Phalan@Sun.COM      * Solaris Kerberos:
39647934SMark.Phalan@Sun.COM      * If C_Initialize was already called by the process before the pkinit
39657934SMark.Phalan@Sun.COM      * module was loaded then record that fact.
39667934SMark.Phalan@Sun.COM      * "finalize_pkcs11" is used by pkinit_fini_pkcs11 to determine whether
39677934SMark.Phalan@Sun.COM      * or not C_Finalize() should be called.
39687934SMark.Phalan@Sun.COM      */
39697934SMark.Phalan@Sun.COM      cctx->finalize_pkcs11 =
39707934SMark.Phalan@Sun.COM 	(r == CKR_CRYPTOKI_ALREADY_INITIALIZED ? FALSE : TRUE);
3971*12945Swill.fiveash@oracle.com     /*
3972*12945Swill.fiveash@oracle.com      * First make sure that is an applicable slot otherwise fail.
3973*12945Swill.fiveash@oracle.com      *
3974*12945Swill.fiveash@oracle.com      * Start by getting a count of all slots with or without tokens.
3975*12945Swill.fiveash@oracle.com      */
3976*12945Swill.fiveash@oracle.com 
3977*12945Swill.fiveash@oracle.com     if ((r = cctx->p11->C_GetSlotList(FALSE, NULL, &count)) != CKR_OK) {
3978*12945Swill.fiveash@oracle.com 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
3979*12945Swill.fiveash@oracle.com 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3980*12945Swill.fiveash@oracle.com 	    gettext("Error trying to get PKCS11 slot list: %s"),
3981*12945Swill.fiveash@oracle.com 	    pkinit_pkcs11_code_to_text(r));
3982*12945Swill.fiveash@oracle.com 	r = KRB5KDC_ERR_PREAUTH_FAILED;
3983*12945Swill.fiveash@oracle.com 	goto out;
3984*12945Swill.fiveash@oracle.com     }
398512944Swill.fiveash@oracle.com 
398612944Swill.fiveash@oracle.com     if (count == 0) {
3987*12945Swill.fiveash@oracle.com 	/* There are no slots so bail */
398812944Swill.fiveash@oracle.com 	r = KRB5KDC_ERR_PREAUTH_FAILED;
398912944Swill.fiveash@oracle.com 	krb5_set_error_message(context, r,
3990*12945Swill.fiveash@oracle.com 			       gettext("No PKCS11 slots found"));
3991*12945Swill.fiveash@oracle.com 	pkiDebug("pkinit_open_session: no slots, count: %d\n", count);
399212944Swill.fiveash@oracle.com 	goto out;
3993*12945Swill.fiveash@oracle.com     } else if (cctx->slotid != PK_NOSLOT) {
3994*12945Swill.fiveash@oracle.com 	/* See if any of the slots match the specified slotID */
3995*12945Swill.fiveash@oracle.com 	tmpslotlist = malloc(count * sizeof (CK_SLOT_ID));
3996*12945Swill.fiveash@oracle.com 	if (tmpslotlist == NULL) {
3997*12945Swill.fiveash@oracle.com 	    krb5_set_error_message(context, ENOMEM,
3998*12945Swill.fiveash@oracle.com 				   gettext("Memory allocation error:"));
3999*12945Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4000*12945Swill.fiveash@oracle.com 	    goto out;
4001*12945Swill.fiveash@oracle.com 	}
4002*12945Swill.fiveash@oracle.com 	if ((r = cctx->p11->C_GetSlotList(FALSE, tmpslotlist, &count)) != CKR_OK) {
4003*12945Swill.fiveash@oracle.com 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4004*12945Swill.fiveash@oracle.com 				   gettext("Error trying to get PKCS11 slot list: %s"),
4005*12945Swill.fiveash@oracle.com 				   pkinit_pkcs11_code_to_text(r));
4006*12945Swill.fiveash@oracle.com 	    pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4007*12945Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4008*12945Swill.fiveash@oracle.com 	    goto out;
4009*12945Swill.fiveash@oracle.com 	}
4010*12945Swill.fiveash@oracle.com 
4011*12945Swill.fiveash@oracle.com 	for (i = 0; i < count && cctx->slotid != tmpslotlist[i]; i++)
4012*12945Swill.fiveash@oracle.com 	    continue;
4013*12945Swill.fiveash@oracle.com 
4014*12945Swill.fiveash@oracle.com 	if (i >= count) {
4015*12945Swill.fiveash@oracle.com 	    /* no slots match */
4016*12945Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4017*12945Swill.fiveash@oracle.com 	    krb5_set_error_message(context, r,
4018*12945Swill.fiveash@oracle.com 				   gettext("Requested PKCS11 slot ID %d not found"),
4019*12945Swill.fiveash@oracle.com 				   cctx->slotid);
4020*12945Swill.fiveash@oracle.com 	    pkiDebug("open_session: no matching slot found for slotID %d\n",
4021*12945Swill.fiveash@oracle.com 		     cctx->slotid);
4022*12945Swill.fiveash@oracle.com 	    goto out;
4023*12945Swill.fiveash@oracle.com 	}
4024*12945Swill.fiveash@oracle.com     }
4025*12945Swill.fiveash@oracle.com 
4026*12945Swill.fiveash@oracle.com tryagain:
4027*12945Swill.fiveash@oracle.com     /* get count of slots that have tokens */
4028*12945Swill.fiveash@oracle.com     if ((r = cctx->p11->C_GetSlotList(TRUE, NULL, &count)) != CKR_OK) {
4029*12945Swill.fiveash@oracle.com 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4030*12945Swill.fiveash@oracle.com 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4031*12945Swill.fiveash@oracle.com 			       gettext("Error trying to get PKCS11 slot list: %s"),
4032*12945Swill.fiveash@oracle.com 			       pkinit_pkcs11_code_to_text(r));
4033*12945Swill.fiveash@oracle.com 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4034*12945Swill.fiveash@oracle.com 	goto out;
4035*12945Swill.fiveash@oracle.com     }
4036*12945Swill.fiveash@oracle.com 
4037*12945Swill.fiveash@oracle.com     if (count == 0) {
4038*12945Swill.fiveash@oracle.com 	/*
4039*12945Swill.fiveash@oracle.com 	 * Note, never prompt if !do_matching as this implies KDC side
4040*12945Swill.fiveash@oracle.com 	 * processing
4041*12945Swill.fiveash@oracle.com 	 */
4042*12945Swill.fiveash@oracle.com 	if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4043*12945Swill.fiveash@oracle.com 	    /* found slot(s) but no token so prompt and try again */
4044*12945Swill.fiveash@oracle.com 	    if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4045*12945Swill.fiveash@oracle.com 		cctx->p11flags |= C_PROMPTED_USER;
4046*12945Swill.fiveash@oracle.com 		goto tryagain;
4047*12945Swill.fiveash@oracle.com 	    } else {
4048*12945Swill.fiveash@oracle.com 		pkiDebug("open_session: prompt for token/smart card failed\n");
4049*12945Swill.fiveash@oracle.com 		krb5_set_error_message(context, r,
4050*12945Swill.fiveash@oracle.com 				       gettext("Prompt for token/smart card failed"));
4051*12945Swill.fiveash@oracle.com 		r = KRB5KDC_ERR_PREAUTH_FAILED;
4052*12945Swill.fiveash@oracle.com 		goto out;
4053*12945Swill.fiveash@oracle.com 	    }
4054*12945Swill.fiveash@oracle.com 
4055*12945Swill.fiveash@oracle.com 	} else {
4056*12945Swill.fiveash@oracle.com 	    /* already prompted once so bailing */
4057*12945Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4058*12945Swill.fiveash@oracle.com 	    krb5_set_error_message(context, r,
4059*12945Swill.fiveash@oracle.com 				   gettext("No smart card tokens found"));
4060*12945Swill.fiveash@oracle.com 	    pkiDebug("pkinit_open_session: no token, already prompted\n");
4061*12945Swill.fiveash@oracle.com 	    goto out;
4062*12945Swill.fiveash@oracle.com 	}
4063*12945Swill.fiveash@oracle.com     }
4064*12945Swill.fiveash@oracle.com 
4065*12945Swill.fiveash@oracle.com     if (slotlist != NULL)
4066*12945Swill.fiveash@oracle.com 	free(slotlist);
4067*12945Swill.fiveash@oracle.com 
406812944Swill.fiveash@oracle.com     slotlist = malloc(count * sizeof (CK_SLOT_ID));
406912944Swill.fiveash@oracle.com     if (slotlist == NULL) {
407012944Swill.fiveash@oracle.com 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
407112944Swill.fiveash@oracle.com 			       gettext("Memory allocation error"));
407212944Swill.fiveash@oracle.com 	r = KRB5KDC_ERR_PREAUTH_FAILED;
407312944Swill.fiveash@oracle.com 	goto out;
407412944Swill.fiveash@oracle.com     }
407512944Swill.fiveash@oracle.com     /*
407612944Swill.fiveash@oracle.com      * Solaris Kerberos: get list of PKCS11 slotid's that have tokens.
407712944Swill.fiveash@oracle.com      */
407812944Swill.fiveash@oracle.com     if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
407912944Swill.fiveash@oracle.com 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
408012944Swill.fiveash@oracle.com 			       gettext("Error trying to get PKCS11 slot list: %s"),
408112944Swill.fiveash@oracle.com 			       pkinit_pkcs11_code_to_text(r));
4082*12945Swill.fiveash@oracle.com 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
408312944Swill.fiveash@oracle.com 	r = KRB5KDC_ERR_PREAUTH_FAILED;
408412944Swill.fiveash@oracle.com 	goto out;
40857934SMark.Phalan@Sun.COM     }
40867934SMark.Phalan@Sun.COM 
4087*12945Swill.fiveash@oracle.com     token_choices.numtokens = 0;
4088*12945Swill.fiveash@oracle.com     token_choices.token_array = malloc(count * sizeof (*token_choices.token_array));
4089*12945Swill.fiveash@oracle.com     if (token_choices.token_array == NULL) {
4090*12945Swill.fiveash@oracle.com 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4091*12945Swill.fiveash@oracle.com 	krb5_set_error_message(context, r,
4092*12945Swill.fiveash@oracle.com 			       gettext("Memory allocation error"));
4093*12945Swill.fiveash@oracle.com 	goto out;
4094*12945Swill.fiveash@oracle.com     }
4095*12945Swill.fiveash@oracle.com 
4096*12945Swill.fiveash@oracle.com     /* examine all the tokens */
40977934SMark.Phalan@Sun.COM     for (i = 0; i < count; i++) {
409812944Swill.fiveash@oracle.com 	/*
409912944Swill.fiveash@oracle.com 	 * Solaris Kerberos: if a slotid was specified skip slots that don't
410012944Swill.fiveash@oracle.com 	 * match.
410112944Swill.fiveash@oracle.com 	 */
410212944Swill.fiveash@oracle.com 	if (cctx->slotid != PK_NOSLOT && cctx->slotid != slotlist[i])
410312944Swill.fiveash@oracle.com 	    continue;
4104*12945Swill.fiveash@oracle.com 
41057934SMark.Phalan@Sun.COM 	/* Open session */
41067934SMark.Phalan@Sun.COM 	if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
4107*12945Swill.fiveash@oracle.com 					  NULL, NULL, &tmpsession)) != CKR_OK) {
41087934SMark.Phalan@Sun.COM 	    pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r));
410912944Swill.fiveash@oracle.com 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4110*12945Swill.fiveash@oracle.com 				   gettext("Error trying to open PKCS11 session: %s"),
4111*12945Swill.fiveash@oracle.com 				   pkinit_pkcs11_code_to_text(r));
411212944Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
411312944Swill.fiveash@oracle.com 	    goto out;
41147934SMark.Phalan@Sun.COM 	}
41157934SMark.Phalan@Sun.COM 
41167934SMark.Phalan@Sun.COM 	/* Get token info */
41177934SMark.Phalan@Sun.COM 	if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) {
41187934SMark.Phalan@Sun.COM 	    pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r));
411912944Swill.fiveash@oracle.com 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4120*12945Swill.fiveash@oracle.com 				   gettext("Error trying to read PKCS11 token: %s"),
4121*12945Swill.fiveash@oracle.com 				   pkinit_pkcs11_code_to_text(r));
412212944Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4123*12945Swill.fiveash@oracle.com 	    cctx->p11->C_CloseSession(tmpsession);
412412944Swill.fiveash@oracle.com 	    goto out;
41257934SMark.Phalan@Sun.COM 	}
412612943Swill.fiveash@oracle.com 
412712943Swill.fiveash@oracle.com 	if (cctx->token_label == NULL) {
4128*12945Swill.fiveash@oracle.com 	    /*
4129*12945Swill.fiveash@oracle.com              * If the token doesn't require login to examine the certs then
4130*12945Swill.fiveash@oracle.com              * let's check the certs out to see if any match the criteria if
4131*12945Swill.fiveash@oracle.com              * any.
4132*12945Swill.fiveash@oracle.com              */
4133*12945Swill.fiveash@oracle.com 	    if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4134*12945Swill.fiveash@oracle.com 		/*
4135*12945Swill.fiveash@oracle.com 		 * It's okay to check the certs if we don't have to login but
4136*12945Swill.fiveash@oracle.com 		 * don't load the certs onto cctx at this point, this will be
4137*12945Swill.fiveash@oracle.com 		 * done later in this function for the chosen token.
4138*12945Swill.fiveash@oracle.com 		 */
4139*12945Swill.fiveash@oracle.com 		if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4140*12945Swill.fiveash@oracle.com 					  req_cryptoctx, cctx, princ,
4141*12945Swill.fiveash@oracle.com 					  do_matching, 0)) == 0) {
4142*12945Swill.fiveash@oracle.com 		    tokenmatch = TRUE;
4143*12945Swill.fiveash@oracle.com 		} else if (r != ENOENT){
4144*12945Swill.fiveash@oracle.com 		    r = KRB5KDC_ERR_PREAUTH_FAILED;
4145*12945Swill.fiveash@oracle.com 		    cctx->p11->C_CloseSession(tmpsession);
4146*12945Swill.fiveash@oracle.com 		    goto out;
4147*12945Swill.fiveash@oracle.com 		} else {
4148*12945Swill.fiveash@oracle.com 		    /* ignore ENOENT here */
4149*12945Swill.fiveash@oracle.com 		    r = 0;
4150*12945Swill.fiveash@oracle.com 		}
4151*12945Swill.fiveash@oracle.com 	    } else {
4152*12945Swill.fiveash@oracle.com                 tokenmatch = TRUE;
4153*12945Swill.fiveash@oracle.com             }
415412943Swill.fiveash@oracle.com 	} else {
415512943Swill.fiveash@oracle.com 	    /* + 1 so tokenlabelstr can be \0 terminated */
415612943Swill.fiveash@oracle.com 	    char tokenlabelstr[sizeof (tinfo.label) + 1];
415712943Swill.fiveash@oracle.com 
415812943Swill.fiveash@oracle.com 	    /*
4159*12945Swill.fiveash@oracle.com 	     * Convert token label into C string with trailing white space
4160*12945Swill.fiveash@oracle.com 	     * trimmed.
416112943Swill.fiveash@oracle.com 	     */
4162*12945Swill.fiveash@oracle.com 	    trim_token_label(&tinfo, tokenlabelstr, sizeof (tokenlabelstr));
416312943Swill.fiveash@oracle.com 
416412943Swill.fiveash@oracle.com 	    pkiDebug("open_session: slotid %d token found: \"%s\", "
416512943Swill.fiveash@oracle.com 		     "cctx->token_label: \"%s\"\n",
416612943Swill.fiveash@oracle.com 		     slotlist[i], tokenlabelstr, (char *) cctx->token_label);
4167*12945Swill.fiveash@oracle.com 
416812943Swill.fiveash@oracle.com 	    if (!strcmp(cctx->token_label, tokenlabelstr)) {
4169*12945Swill.fiveash@oracle.com 		if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4170*12945Swill.fiveash@oracle.com 		    /*
4171*12945Swill.fiveash@oracle.com 		     * It's okay to check the certs if we don't have to login but
4172*12945Swill.fiveash@oracle.com 		     * don't load the certs onto cctx at this point, this will be
4173*12945Swill.fiveash@oracle.com 		     * done later in this function for the chosen token.
4174*12945Swill.fiveash@oracle.com 		     */
4175*12945Swill.fiveash@oracle.com 		    if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4176*12945Swill.fiveash@oracle.com 					      req_cryptoctx, cctx, princ,
4177*12945Swill.fiveash@oracle.com 					      do_matching, 0)) == 0) {
4178*12945Swill.fiveash@oracle.com 			tokenmatch = TRUE;
4179*12945Swill.fiveash@oracle.com 		    } else if (r != ENOENT){
4180*12945Swill.fiveash@oracle.com 			r = KRB5KDC_ERR_PREAUTH_FAILED;
4181*12945Swill.fiveash@oracle.com 			cctx->p11->C_CloseSession(tmpsession);
4182*12945Swill.fiveash@oracle.com 			goto out;
4183*12945Swill.fiveash@oracle.com 		    } else {
4184*12945Swill.fiveash@oracle.com 			/* ignore ENOENT here */
4185*12945Swill.fiveash@oracle.com 			r = 0;
4186*12945Swill.fiveash@oracle.com 		    }
4187*12945Swill.fiveash@oracle.com 		} else {
4188*12945Swill.fiveash@oracle.com 		    tokenmatch = TRUE;
4189*12945Swill.fiveash@oracle.com 		}
419012943Swill.fiveash@oracle.com 	    }
419112943Swill.fiveash@oracle.com 	}
4192*12945Swill.fiveash@oracle.com 
4193*12945Swill.fiveash@oracle.com 	if (tokenmatch == TRUE) {
4194*12945Swill.fiveash@oracle.com 	    /* add the token to token_choices.token_array */
4195*12945Swill.fiveash@oracle.com 	    token_choices.token_array[token_choices.numtokens].slotID = slotlist[i];
4196*12945Swill.fiveash@oracle.com 	    token_choices.token_array[token_choices.numtokens].session = tmpsession;
4197*12945Swill.fiveash@oracle.com 	    token_choices.token_array[token_choices.numtokens].token_info = tinfo;
4198*12945Swill.fiveash@oracle.com 	    token_choices.numtokens++;
4199*12945Swill.fiveash@oracle.com             /* !do_matching implies we take the first matching token */
4200*12945Swill.fiveash@oracle.com             if (!do_matching)
4201*12945Swill.fiveash@oracle.com                 break;
4202*12945Swill.fiveash@oracle.com             else
4203*12945Swill.fiveash@oracle.com                 tokenmatch = FALSE;
4204*12945Swill.fiveash@oracle.com 	} else {
4205*12945Swill.fiveash@oracle.com 	    cctx->p11->C_CloseSession(tmpsession);
4206*12945Swill.fiveash@oracle.com 	}
4207*12945Swill.fiveash@oracle.com     }
4208*12945Swill.fiveash@oracle.com 
4209*12945Swill.fiveash@oracle.com     if (token_choices.numtokens == 0) {
4210*12945Swill.fiveash@oracle.com 	/*
4211*12945Swill.fiveash@oracle.com 	 * Solaris Kerberos: prompt for token one time if there was no token
4212*12945Swill.fiveash@oracle.com          * and do_matching is 1 (see earlier comment about do_matching).
4213*12945Swill.fiveash@oracle.com 	 */
4214*12945Swill.fiveash@oracle.com 	if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4215*12945Swill.fiveash@oracle.com 	    if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4216*12945Swill.fiveash@oracle.com                 cctx->p11flags |= C_PROMPTED_USER;
4217*12945Swill.fiveash@oracle.com 		goto tryagain;
4218*12945Swill.fiveash@oracle.com 	    } else {
4219*12945Swill.fiveash@oracle.com 		pkiDebug("open_session: prompt for token/smart card failed\n");
4220*12945Swill.fiveash@oracle.com 		krb5_set_error_message(context, r,
4221*12945Swill.fiveash@oracle.com 				       gettext("Prompt for token/smart card failed"));
4222*12945Swill.fiveash@oracle.com 		r = KRB5KDC_ERR_PREAUTH_FAILED;
4223*12945Swill.fiveash@oracle.com 		goto out;
4224*12945Swill.fiveash@oracle.com 	    }
4225*12945Swill.fiveash@oracle.com 	} else {
4226*12945Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4227*12945Swill.fiveash@oracle.com 	    krb5_set_error_message(context, r,
4228*12945Swill.fiveash@oracle.com 				   gettext("No smart card tokens found"));
4229*12945Swill.fiveash@oracle.com 	    pkiDebug("open_session: no matching token found\n");
4230*12945Swill.fiveash@oracle.com 	    goto out;
4231*12945Swill.fiveash@oracle.com 	}
4232*12945Swill.fiveash@oracle.com     } else if (token_choices.numtokens == 1) {
4233*12945Swill.fiveash@oracle.com         if ((token_choices.token_array[0].token_info.flags & CKF_LOGIN_REQUIRED) &&
4234*12945Swill.fiveash@oracle.com             !(cctx->p11flags & C_PROMPTED_USER) &&
4235*12945Swill.fiveash@oracle.com             do_matching) {
4236*12945Swill.fiveash@oracle.com             if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4237*12945Swill.fiveash@oracle.com                 pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4238*12945Swill.fiveash@oracle.com                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4239*12945Swill.fiveash@oracle.com                 krb5_set_error_message(context, r,
4240*12945Swill.fiveash@oracle.com                                        gettext("Prompt for token/smart card failed"));
4241*12945Swill.fiveash@oracle.com                 goto out;
4242*12945Swill.fiveash@oracle.com             }
4243*12945Swill.fiveash@oracle.com             if (choice == RESCAN_TOKENS) {
4244*12945Swill.fiveash@oracle.com                 /* rescan for new smartcard/token */
4245*12945Swill.fiveash@oracle.com                 for (i = 0; i < token_choices.numtokens; i++) {
4246*12945Swill.fiveash@oracle.com                     /* close all sessions */
4247*12945Swill.fiveash@oracle.com                     cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4248*12945Swill.fiveash@oracle.com                 }
4249*12945Swill.fiveash@oracle.com                 free(token_choices.token_array);
4250*12945Swill.fiveash@oracle.com                 token_choices.token_array = NULL;
4251*12945Swill.fiveash@oracle.com                 token_choices.numtokens = 0;
4252*12945Swill.fiveash@oracle.com                 goto tryagain;
4253*12945Swill.fiveash@oracle.com             } else if (choice == SKIP_TOKENS) {
4254*12945Swill.fiveash@oracle.com                 /* do not use smartcard/token for auth */
4255*12945Swill.fiveash@oracle.com                 cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4256*12945Swill.fiveash@oracle.com                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4257*12945Swill.fiveash@oracle.com                 goto out;
4258*12945Swill.fiveash@oracle.com             } else {
4259*12945Swill.fiveash@oracle.com                 cctx->p11flags |= C_PROMPTED_USER;
4260*12945Swill.fiveash@oracle.com             }
4261*12945Swill.fiveash@oracle.com         } else {
4262*12945Swill.fiveash@oracle.com             choice = 0; /* really the only choice is the first token_array entry */
4263*12945Swill.fiveash@oracle.com         }
4264*12945Swill.fiveash@oracle.com     } else if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4265*12945Swill.fiveash@oracle.com 	/* > 1 token so present menu of token choices, let the user decide. */
4266*12945Swill.fiveash@oracle.com 	if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4267*12945Swill.fiveash@oracle.com 	    pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4268*12945Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4269*12945Swill.fiveash@oracle.com 	    krb5_set_error_message(context, r,
4270*12945Swill.fiveash@oracle.com 				   gettext("Prompt for token/smart card failed"));
4271*12945Swill.fiveash@oracle.com 	    goto out;
4272*12945Swill.fiveash@oracle.com 	}
4273*12945Swill.fiveash@oracle.com 	if (choice == RESCAN_TOKENS) {
4274*12945Swill.fiveash@oracle.com 	    /* rescan for new smartcard/token */
4275*12945Swill.fiveash@oracle.com 	    for (i = 0; i < token_choices.numtokens; i++) {
4276*12945Swill.fiveash@oracle.com 		/* close all sessions */
4277*12945Swill.fiveash@oracle.com 		cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4278*12945Swill.fiveash@oracle.com 	    }
4279*12945Swill.fiveash@oracle.com 	    free(token_choices.token_array);
4280*12945Swill.fiveash@oracle.com 	    token_choices.token_array = NULL;
4281*12945Swill.fiveash@oracle.com 	    token_choices.numtokens = 0;
4282*12945Swill.fiveash@oracle.com 	    goto tryagain;
4283*12945Swill.fiveash@oracle.com 	} else if (choice == SKIP_TOKENS) {
4284*12945Swill.fiveash@oracle.com 	    /* do not use smartcard/token for auth */
4285*12945Swill.fiveash@oracle.com             cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4286*12945Swill.fiveash@oracle.com 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4287*12945Swill.fiveash@oracle.com 	    goto out;
4288*12945Swill.fiveash@oracle.com 	} else {
4289*12945Swill.fiveash@oracle.com             cctx->p11flags |= C_PROMPTED_USER;
4290*12945Swill.fiveash@oracle.com         }
4291*12945Swill.fiveash@oracle.com     } else {
4292*12945Swill.fiveash@oracle.com         r = KRB5KDC_ERR_PREAUTH_FAILED;
4293*12945Swill.fiveash@oracle.com         goto out;
4294*12945Swill.fiveash@oracle.com     }
4295*12945Swill.fiveash@oracle.com 
4296*12945Swill.fiveash@oracle.com     cctx->slotid = token_choices.token_array[choice].slotID;
4297*12945Swill.fiveash@oracle.com     cctx->session = token_choices.token_array[choice].session;
429812944Swill.fiveash@oracle.com 
42997934SMark.Phalan@Sun.COM     pkiDebug("open_session: slotid %d (%d of %d)\n", (int) cctx->slotid,
43007934SMark.Phalan@Sun.COM 	     i + 1, (int) count);
43017934SMark.Phalan@Sun.COM 
43027934SMark.Phalan@Sun.COM     /* Login if needed */
430311781SWill.Fiveash@Sun.COM     /* Solaris Kerberos: added cctx->p11flags check */
4304*12945Swill.fiveash@oracle.com     if ((token_choices.token_array[choice].token_info.flags & CKF_LOGIN_REQUIRED) &&
4305*12945Swill.fiveash@oracle.com         !(cctx->p11flags & C_LOGIN_DONE)) {
4306*12945Swill.fiveash@oracle.com         r = pkinit_login(context, cctx, &token_choices.token_array[choice].token_info);
4307*12945Swill.fiveash@oracle.com     }
4308*12945Swill.fiveash@oracle.com 
4309*12945Swill.fiveash@oracle.com     if (r == 0) {
4310*12945Swill.fiveash@oracle.com 	/* Doing this again to load the certs into cctx. */
4311*12945Swill.fiveash@oracle.com 	r = check_load_certs(context, cctx->session, plg_cryptoctx,
4312*12945Swill.fiveash@oracle.com 			     req_cryptoctx, cctx, princ, do_matching, 1);
4313*12945Swill.fiveash@oracle.com     }
43147934SMark.Phalan@Sun.COM 
431512944Swill.fiveash@oracle.com out:
431612944Swill.fiveash@oracle.com     if (slotlist != NULL)
431712944Swill.fiveash@oracle.com 	free(slotlist);
431812944Swill.fiveash@oracle.com 
4319*12945Swill.fiveash@oracle.com     if (tmpslotlist != NULL)
4320*12945Swill.fiveash@oracle.com 	free(tmpslotlist);
4321*12945Swill.fiveash@oracle.com 
4322*12945Swill.fiveash@oracle.com     if (token_choices.token_array != NULL) {
4323*12945Swill.fiveash@oracle.com 	if (r != 0) {
4324*12945Swill.fiveash@oracle.com 	    /* close all sessions if there's an error */
4325*12945Swill.fiveash@oracle.com 	    for (i = 0; i < token_choices.numtokens; i++) {
4326*12945Swill.fiveash@oracle.com 		cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4327*12945Swill.fiveash@oracle.com 	    }
4328*12945Swill.fiveash@oracle.com 	    cctx->session = CK_INVALID_HANDLE;
4329*12945Swill.fiveash@oracle.com 	} else {
4330*12945Swill.fiveash@oracle.com 	    /* close sessions not chosen */
4331*12945Swill.fiveash@oracle.com 	    for (i = 0; i < token_choices.numtokens; i++) {
4332*12945Swill.fiveash@oracle.com 		if (i != choice) {
4333*12945Swill.fiveash@oracle.com 		    cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4334*12945Swill.fiveash@oracle.com 		}
4335*12945Swill.fiveash@oracle.com 	    }
4336*12945Swill.fiveash@oracle.com 	}
4337*12945Swill.fiveash@oracle.com 	free(token_choices.token_array);
4338*12945Swill.fiveash@oracle.com     }
4339*12945Swill.fiveash@oracle.com 
4340*12945Swill.fiveash@oracle.com     return (r);
43417934SMark.Phalan@Sun.COM }
43427934SMark.Phalan@Sun.COM 
43437934SMark.Phalan@Sun.COM /*
43447934SMark.Phalan@Sun.COM  * Look for a key that's:
43457934SMark.Phalan@Sun.COM  * 1. private
43467934SMark.Phalan@Sun.COM  * 2. capable of the specified operation (usually signing or decrypting)
43477934SMark.Phalan@Sun.COM  * 3. RSA (this may be wrong but it's all we can do for now)
43487934SMark.Phalan@Sun.COM  * 4. matches the id of the cert we chose
43497934SMark.Phalan@Sun.COM  *
43507934SMark.Phalan@Sun.COM  * You must call pkinit_get_certs before calling pkinit_find_private_key
43517934SMark.Phalan@Sun.COM  * (that's because we need the ID of the private key)
43527934SMark.Phalan@Sun.COM  *
43537934SMark.Phalan@Sun.COM  * pkcs11 says the id of the key doesn't have to match that of the cert, but
43547934SMark.Phalan@Sun.COM  * I can't figure out any other way to decide which key to use.
43557934SMark.Phalan@Sun.COM  *
43567934SMark.Phalan@Sun.COM  * We should only find one key that fits all the requirements.
43577934SMark.Phalan@Sun.COM  * If there are more than one, we just take the first one.
43587934SMark.Phalan@Sun.COM  */
43597934SMark.Phalan@Sun.COM 
43607934SMark.Phalan@Sun.COM /* ARGSUSED */
43617934SMark.Phalan@Sun.COM krb5_error_code
pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,CK_ATTRIBUTE_TYPE usage,CK_OBJECT_HANDLE * objp)43627934SMark.Phalan@Sun.COM pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
43637934SMark.Phalan@Sun.COM 			CK_ATTRIBUTE_TYPE usage,
43647934SMark.Phalan@Sun.COM 			CK_OBJECT_HANDLE *objp)
43657934SMark.Phalan@Sun.COM {
43667934SMark.Phalan@Sun.COM     CK_OBJECT_CLASS cls;
43677934SMark.Phalan@Sun.COM     CK_ATTRIBUTE attrs[4];
43687934SMark.Phalan@Sun.COM     CK_ULONG count;
43697934SMark.Phalan@Sun.COM     CK_KEY_TYPE keytype;
43707934SMark.Phalan@Sun.COM     unsigned int nattrs = 0;
43717934SMark.Phalan@Sun.COM     int r;
43727934SMark.Phalan@Sun.COM #ifdef PKINIT_USE_KEY_USAGE
43737934SMark.Phalan@Sun.COM     CK_BBOOL true_false;
43747934SMark.Phalan@Sun.COM #endif
43757934SMark.Phalan@Sun.COM 
43767934SMark.Phalan@Sun.COM     cls = CKO_PRIVATE_KEY;
43777934SMark.Phalan@Sun.COM     attrs[nattrs].type = CKA_CLASS;
43787934SMark.Phalan@Sun.COM     attrs[nattrs].pValue = &cls;
43797934SMark.Phalan@Sun.COM     attrs[nattrs].ulValueLen = sizeof cls;
43807934SMark.Phalan@Sun.COM     nattrs++;
43817934SMark.Phalan@Sun.COM 
43827934SMark.Phalan@Sun.COM #ifdef PKINIT_USE_KEY_USAGE
43837934SMark.Phalan@Sun.COM     /*
43847934SMark.Phalan@Sun.COM      * Some cards get confused if you try to specify a key usage,
43857934SMark.Phalan@Sun.COM      * so don't, and hope for the best. This will fail if you have
43867934SMark.Phalan@Sun.COM      * several keys with the same id and different usages but I have
43877934SMark.Phalan@Sun.COM      * not seen this on real cards.
43887934SMark.Phalan@Sun.COM      */
43897934SMark.Phalan@Sun.COM     true_false = TRUE;
43907934SMark.Phalan@Sun.COM     attrs[nattrs].type = usage;
43917934SMark.Phalan@Sun.COM     attrs[nattrs].pValue = &true_false;
43927934SMark.Phalan@Sun.COM     attrs[nattrs].ulValueLen = sizeof true_false;
43937934SMark.Phalan@Sun.COM     nattrs++;
43947934SMark.Phalan@Sun.COM #endif
43957934SMark.Phalan@Sun.COM 
43967934SMark.Phalan@Sun.COM     keytype = CKK_RSA;
43977934SMark.Phalan@Sun.COM     attrs[nattrs].type = CKA_KEY_TYPE;
43987934SMark.Phalan@Sun.COM     attrs[nattrs].pValue = &keytype;
43997934SMark.Phalan@Sun.COM     attrs[nattrs].ulValueLen = sizeof keytype;
44007934SMark.Phalan@Sun.COM     nattrs++;
44017934SMark.Phalan@Sun.COM 
44027934SMark.Phalan@Sun.COM     attrs[nattrs].type = CKA_ID;
44037934SMark.Phalan@Sun.COM     attrs[nattrs].pValue = id_cryptoctx->cert_id;
44047934SMark.Phalan@Sun.COM     attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
44057934SMark.Phalan@Sun.COM     nattrs++;
44067934SMark.Phalan@Sun.COM 
44077934SMark.Phalan@Sun.COM     r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
44087934SMark.Phalan@Sun.COM     if (r != CKR_OK) {
44097934SMark.Phalan@Sun.COM 	pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
44107934SMark.Phalan@Sun.COM 		 pkinit_pkcs11_code_to_text(r));
44117934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
44127934SMark.Phalan@Sun.COM     }
44137934SMark.Phalan@Sun.COM 
44147934SMark.Phalan@Sun.COM     r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
44157934SMark.Phalan@Sun.COM     id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
44167934SMark.Phalan@Sun.COM     pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
44177934SMark.Phalan@Sun.COM 
44187934SMark.Phalan@Sun.COM     /*
44197934SMark.Phalan@Sun.COM      * Solaris Kerberos:
44207934SMark.Phalan@Sun.COM      * The CKA_ID may not be correctly set for the private key. For e.g. when
44217934SMark.Phalan@Sun.COM      * storing a private key in softtoken pktool(1) doesn't generate or store
44227934SMark.Phalan@Sun.COM      * a CKA_ID for the private key. Another way to identify the private key is
44237934SMark.Phalan@Sun.COM      * to look for a private key with the same RSA modulus as the public key
44247934SMark.Phalan@Sun.COM      * in the certificate.
44257934SMark.Phalan@Sun.COM      */
44267934SMark.Phalan@Sun.COM     if (r == CKR_OK && count != 1) {
44277934SMark.Phalan@Sun.COM 
44287934SMark.Phalan@Sun.COM 	EVP_PKEY *priv;
44297934SMark.Phalan@Sun.COM 	X509 *cert;
44307934SMark.Phalan@Sun.COM 	unsigned int n_len;
44317934SMark.Phalan@Sun.COM 	unsigned char *n_bytes;
44327934SMark.Phalan@Sun.COM 
44337934SMark.Phalan@Sun.COM 	cert = sk_X509_value(id_cryptoctx->my_certs, 0);
44347934SMark.Phalan@Sun.COM 	priv = X509_get_pubkey(cert);
44357934SMark.Phalan@Sun.COM 	if (priv == NULL) {
44367934SMark.Phalan@Sun.COM     		pkiDebug("Failed to extract pub key from cert\n");
44377934SMark.Phalan@Sun.COM 		return KRB5KDC_ERR_PREAUTH_FAILED;
44387934SMark.Phalan@Sun.COM 	}
44397934SMark.Phalan@Sun.COM 
44407934SMark.Phalan@Sun.COM 	nattrs = 0;
44417934SMark.Phalan@Sun.COM 	cls = CKO_PRIVATE_KEY;
44427934SMark.Phalan@Sun.COM 	attrs[nattrs].type = CKA_CLASS;
44437934SMark.Phalan@Sun.COM 	attrs[nattrs].pValue = &cls;
44447934SMark.Phalan@Sun.COM 	attrs[nattrs].ulValueLen = sizeof cls;
44457934SMark.Phalan@Sun.COM 	nattrs++;
44467934SMark.Phalan@Sun.COM 
44477934SMark.Phalan@Sun.COM #ifdef PKINIT_USE_KEY_USAGE
44487934SMark.Phalan@Sun.COM 	true_false = TRUE;
44497934SMark.Phalan@Sun.COM 	attrs[nattrs].type = usage;
44507934SMark.Phalan@Sun.COM 	attrs[nattrs].pValue = &true_false;
44517934SMark.Phalan@Sun.COM 	attrs[nattrs].ulValueLen = sizeof true_false;
44527934SMark.Phalan@Sun.COM 	nattrs++;
44537934SMark.Phalan@Sun.COM #endif
44547934SMark.Phalan@Sun.COM 
44557934SMark.Phalan@Sun.COM 	keytype = CKK_RSA;
44567934SMark.Phalan@Sun.COM 	attrs[nattrs].type = CKA_KEY_TYPE;
44577934SMark.Phalan@Sun.COM 	attrs[nattrs].pValue = &keytype;
44587934SMark.Phalan@Sun.COM 	attrs[nattrs].ulValueLen = sizeof keytype;
44597934SMark.Phalan@Sun.COM 	nattrs++;
44607934SMark.Phalan@Sun.COM 
44617934SMark.Phalan@Sun.COM 	n_len = BN_num_bytes(priv->pkey.rsa->n);
44627934SMark.Phalan@Sun.COM 	n_bytes = (unsigned char *) malloc((size_t) n_len);
44637934SMark.Phalan@Sun.COM 	if (n_bytes == NULL) {
44647934SMark.Phalan@Sun.COM 		return (ENOMEM);
44657934SMark.Phalan@Sun.COM 	}
44667934SMark.Phalan@Sun.COM 
44677934SMark.Phalan@Sun.COM 	if (BN_bn2bin(priv->pkey.rsa->n, n_bytes) == 0) {
44687934SMark.Phalan@Sun.COM 		free (n_bytes);
44697934SMark.Phalan@Sun.COM     		pkiDebug("zero-byte key modulus\n");
44707934SMark.Phalan@Sun.COM 		return KRB5KDC_ERR_PREAUTH_FAILED;
44717934SMark.Phalan@Sun.COM 	}
44727934SMark.Phalan@Sun.COM 
44737934SMark.Phalan@Sun.COM 	attrs[nattrs].type = CKA_MODULUS;
44747934SMark.Phalan@Sun.COM 	attrs[nattrs].ulValueLen = n_len;
44757934SMark.Phalan@Sun.COM 	attrs[nattrs].pValue = n_bytes;
44767934SMark.Phalan@Sun.COM 
44777934SMark.Phalan@Sun.COM 	nattrs++;
44787934SMark.Phalan@Sun.COM 
44797934SMark.Phalan@Sun.COM 	r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
44807934SMark.Phalan@Sun.COM 	free (n_bytes);
44817934SMark.Phalan@Sun.COM 	if (r != CKR_OK) {
44827934SMark.Phalan@Sun.COM 		pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
44837934SMark.Phalan@Sun.COM 			pkinit_pkcs11_code_to_text(r));
44847934SMark.Phalan@Sun.COM 		return KRB5KDC_ERR_PREAUTH_FAILED;
44857934SMark.Phalan@Sun.COM 	}
44867934SMark.Phalan@Sun.COM 
44877934SMark.Phalan@Sun.COM 	r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
44887934SMark.Phalan@Sun.COM 	id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
44897934SMark.Phalan@Sun.COM 	pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
44907934SMark.Phalan@Sun.COM 
44917934SMark.Phalan@Sun.COM     }
44927934SMark.Phalan@Sun.COM 
44937934SMark.Phalan@Sun.COM     if (r != CKR_OK || count < 1)
44947934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
44957934SMark.Phalan@Sun.COM     return 0;
44967934SMark.Phalan@Sun.COM }
44977934SMark.Phalan@Sun.COM #endif
44987934SMark.Phalan@Sun.COM 
44997934SMark.Phalan@Sun.COM /* ARGSUSED */
45007934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_decode_data_fs(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** decoded_data,unsigned int * decoded_data_len)45017934SMark.Phalan@Sun.COM pkinit_decode_data_fs(krb5_context context,
45027934SMark.Phalan@Sun.COM 		      pkinit_identity_crypto_context id_cryptoctx,
45037934SMark.Phalan@Sun.COM 		      unsigned char *data,
45047934SMark.Phalan@Sun.COM 		      unsigned int data_len,
45057934SMark.Phalan@Sun.COM 		      unsigned char **decoded_data,
45067934SMark.Phalan@Sun.COM 		      unsigned int *decoded_data_len)
45077934SMark.Phalan@Sun.COM {
45087934SMark.Phalan@Sun.COM     if (decode_data(decoded_data, decoded_data_len, data, data_len,
45097934SMark.Phalan@Sun.COM 		id_cryptoctx->my_key, sk_X509_value(id_cryptoctx->my_certs,
45107934SMark.Phalan@Sun.COM 		id_cryptoctx->cert_index)) <= 0) {
45117934SMark.Phalan@Sun.COM 	pkiDebug("failed to decode data\n");
45127934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
45137934SMark.Phalan@Sun.COM     }
45147934SMark.Phalan@Sun.COM     return 0;
45157934SMark.Phalan@Sun.COM }
45167934SMark.Phalan@Sun.COM 
45177934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
45187934SMark.Phalan@Sun.COM #ifdef SILLYDECRYPT
45197934SMark.Phalan@Sun.COM CK_RV
pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)45207934SMark.Phalan@Sun.COM pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
45217934SMark.Phalan@Sun.COM 		 CK_BYTE_PTR pEncryptedData,
45227934SMark.Phalan@Sun.COM 		 CK_ULONG  ulEncryptedDataLen,
45237934SMark.Phalan@Sun.COM 		 CK_BYTE_PTR pData,
45247934SMark.Phalan@Sun.COM 		 CK_ULONG_PTR pulDataLen)
45257934SMark.Phalan@Sun.COM {
45267934SMark.Phalan@Sun.COM     CK_RV rv = CKR_OK;
45277934SMark.Phalan@Sun.COM 
45287934SMark.Phalan@Sun.COM     rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
45297934SMark.Phalan@Sun.COM 	ulEncryptedDataLen, pData, pulDataLen);
45307934SMark.Phalan@Sun.COM     if (rv == CKR_OK) {
45317934SMark.Phalan@Sun.COM 	pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
45327934SMark.Phalan@Sun.COM     }
45337934SMark.Phalan@Sun.COM     return rv;
45347934SMark.Phalan@Sun.COM }
45357934SMark.Phalan@Sun.COM #endif
45367934SMark.Phalan@Sun.COM 
45377934SMark.Phalan@Sun.COM static krb5_error_code
pkinit_decode_data_pkcs11(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** decoded_data,unsigned int * decoded_data_len)45387934SMark.Phalan@Sun.COM pkinit_decode_data_pkcs11(krb5_context context,
45397934SMark.Phalan@Sun.COM 			  pkinit_identity_crypto_context id_cryptoctx,
45407934SMark.Phalan@Sun.COM 			  unsigned char *data,
45417934SMark.Phalan@Sun.COM 			  unsigned int data_len,
45427934SMark.Phalan@Sun.COM 			  unsigned char **decoded_data,
45437934SMark.Phalan@Sun.COM 			  unsigned int *decoded_data_len)
45447934SMark.Phalan@Sun.COM {
45457934SMark.Phalan@Sun.COM     CK_OBJECT_HANDLE obj;
45467934SMark.Phalan@Sun.COM     CK_ULONG len;
45477934SMark.Phalan@Sun.COM     CK_MECHANISM mech;
45487934SMark.Phalan@Sun.COM     unsigned char *cp;
45497934SMark.Phalan@Sun.COM     int r;
45507934SMark.Phalan@Sun.COM 
4551*12945Swill.fiveash@oracle.com     /*
4552*12945Swill.fiveash@oracle.com      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4553*12945Swill.fiveash@oracle.com      * loaded.
4554*12945Swill.fiveash@oracle.com      */
4555*12945Swill.fiveash@oracle.com     assert(id_cryptoctx->p11 != NULL);
45567934SMark.Phalan@Sun.COM 
455711781SWill.Fiveash@Sun.COM     /* Solaris Kerberos: Login, if needed, to access private object */
455811781SWill.Fiveash@Sun.COM     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
455911781SWill.Fiveash@Sun.COM         CK_TOKEN_INFO tinfo;
456011781SWill.Fiveash@Sun.COM 
456111781SWill.Fiveash@Sun.COM         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
456211781SWill.Fiveash@Sun.COM         if (r != 0)
456311781SWill.Fiveash@Sun.COM             return r;
456411781SWill.Fiveash@Sun.COM 
456511781SWill.Fiveash@Sun.COM         r = pkinit_login(context, id_cryptoctx, &tinfo);
456611781SWill.Fiveash@Sun.COM         if (r != 0)
456711781SWill.Fiveash@Sun.COM             return r;
456811781SWill.Fiveash@Sun.COM     }
456911781SWill.Fiveash@Sun.COM 
45707934SMark.Phalan@Sun.COM     r = pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj);
45717934SMark.Phalan@Sun.COM     if (r != 0)
45727934SMark.Phalan@Sun.COM 	return r;
45737934SMark.Phalan@Sun.COM 
45747934SMark.Phalan@Sun.COM     mech.mechanism = CKM_RSA_PKCS;
45757934SMark.Phalan@Sun.COM     mech.pParameter = NULL;
45767934SMark.Phalan@Sun.COM     mech.ulParameterLen = 0;
45777934SMark.Phalan@Sun.COM 
45787934SMark.Phalan@Sun.COM     if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech,
45797934SMark.Phalan@Sun.COM 	    obj)) != CKR_OK) {
45807934SMark.Phalan@Sun.COM 	pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
45817934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
45827934SMark.Phalan@Sun.COM     }
45837934SMark.Phalan@Sun.COM     pkiDebug("data_len = %d\n", data_len);
45847934SMark.Phalan@Sun.COM     cp = (unsigned char *)malloc((size_t) data_len);
45857934SMark.Phalan@Sun.COM     if (cp == NULL)
45867934SMark.Phalan@Sun.COM 	return ENOMEM;
45877934SMark.Phalan@Sun.COM     len = data_len;
45887934SMark.Phalan@Sun.COM #ifdef SILLYDECRYPT
45897934SMark.Phalan@Sun.COM     pkiDebug("session %x edata %x edata_len %d data %x datalen @%x %d\n",
45907934SMark.Phalan@Sun.COM 	    (int) id_cryptoctx->session, (int) data, (int) data_len, (int) cp,
45917934SMark.Phalan@Sun.COM 	    (int) &len, (int) len);
45927934SMark.Phalan@Sun.COM     if ((r = pkinit_C_Decrypt(id_cryptoctx, data, (CK_ULONG) data_len,
45937934SMark.Phalan@Sun.COM 	    cp, &len)) != CKR_OK) {
45947934SMark.Phalan@Sun.COM #else
45957934SMark.Phalan@Sun.COM     if ((r = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, data,
45967934SMark.Phalan@Sun.COM 	    (CK_ULONG) data_len, cp, &len)) != CKR_OK) {
45977934SMark.Phalan@Sun.COM #endif
45987934SMark.Phalan@Sun.COM 	pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
45997934SMark.Phalan@Sun.COM 	if (r == CKR_BUFFER_TOO_SMALL)
46007934SMark.Phalan@Sun.COM 	    pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
46017934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
46027934SMark.Phalan@Sun.COM     }
46037934SMark.Phalan@Sun.COM     pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
46047934SMark.Phalan@Sun.COM     *decoded_data_len = len;
46057934SMark.Phalan@Sun.COM     *decoded_data = cp;
46067934SMark.Phalan@Sun.COM 
46077934SMark.Phalan@Sun.COM     return 0;
46087934SMark.Phalan@Sun.COM }
46097934SMark.Phalan@Sun.COM #endif
46107934SMark.Phalan@Sun.COM 
46117934SMark.Phalan@Sun.COM krb5_error_code
46127934SMark.Phalan@Sun.COM pkinit_decode_data(krb5_context context,
46137934SMark.Phalan@Sun.COM 		   pkinit_identity_crypto_context id_cryptoctx,
46147934SMark.Phalan@Sun.COM 		   unsigned char *data,
46157934SMark.Phalan@Sun.COM 		   unsigned int data_len,
46167934SMark.Phalan@Sun.COM 		   unsigned char **decoded_data,
46177934SMark.Phalan@Sun.COM 		   unsigned int *decoded_data_len)
46187934SMark.Phalan@Sun.COM {
46197934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
46207934SMark.Phalan@Sun.COM 
46217934SMark.Phalan@Sun.COM     if (id_cryptoctx->pkcs11_method != 1)
46227934SMark.Phalan@Sun.COM 	retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len,
46237934SMark.Phalan@Sun.COM 	    decoded_data, decoded_data_len);
46247934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
46257934SMark.Phalan@Sun.COM     else
46267934SMark.Phalan@Sun.COM 	retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data,
46277934SMark.Phalan@Sun.COM 	    data_len, decoded_data, decoded_data_len);
46287934SMark.Phalan@Sun.COM #endif
46297934SMark.Phalan@Sun.COM 
46307934SMark.Phalan@Sun.COM     return retval;
46317934SMark.Phalan@Sun.COM }
46327934SMark.Phalan@Sun.COM 
46337934SMark.Phalan@Sun.COM /* ARGSUSED */
46347934SMark.Phalan@Sun.COM static krb5_error_code
46357934SMark.Phalan@Sun.COM pkinit_sign_data_fs(krb5_context context,
46367934SMark.Phalan@Sun.COM 		 pkinit_identity_crypto_context id_cryptoctx,
46377934SMark.Phalan@Sun.COM 		 unsigned char *data,
46387934SMark.Phalan@Sun.COM 		 unsigned int data_len,
46397934SMark.Phalan@Sun.COM 		 unsigned char **sig,
46407934SMark.Phalan@Sun.COM 		 unsigned int *sig_len)
46417934SMark.Phalan@Sun.COM {
46427934SMark.Phalan@Sun.COM     if (create_signature(sig, sig_len, data, data_len,
46437934SMark.Phalan@Sun.COM 	    id_cryptoctx->my_key) != 0) {
46447934SMark.Phalan@Sun.COM 	    pkiDebug("failed to create the signature\n");
46457934SMark.Phalan@Sun.COM 	    return KRB5KDC_ERR_PREAUTH_FAILED;
46467934SMark.Phalan@Sun.COM     }
46477934SMark.Phalan@Sun.COM     return 0;
46487934SMark.Phalan@Sun.COM }
46497934SMark.Phalan@Sun.COM 
46507934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
46517934SMark.Phalan@Sun.COM static krb5_error_code
46527934SMark.Phalan@Sun.COM pkinit_sign_data_pkcs11(krb5_context context,
46537934SMark.Phalan@Sun.COM 			pkinit_identity_crypto_context id_cryptoctx,
46547934SMark.Phalan@Sun.COM 			unsigned char *data,
46557934SMark.Phalan@Sun.COM 			unsigned int data_len,
46567934SMark.Phalan@Sun.COM 			unsigned char **sig,
46577934SMark.Phalan@Sun.COM 			unsigned int *sig_len)
46587934SMark.Phalan@Sun.COM {
46597934SMark.Phalan@Sun.COM     CK_OBJECT_HANDLE obj;
46607934SMark.Phalan@Sun.COM     CK_ULONG len;
46617934SMark.Phalan@Sun.COM     CK_MECHANISM mech;
46627934SMark.Phalan@Sun.COM     unsigned char *cp;
46637934SMark.Phalan@Sun.COM     int r;
46647934SMark.Phalan@Sun.COM 
4665*12945Swill.fiveash@oracle.com     /*
4666*12945Swill.fiveash@oracle.com      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4667*12945Swill.fiveash@oracle.com      * loaded.
4668*12945Swill.fiveash@oracle.com      */
4669*12945Swill.fiveash@oracle.com     assert(id_cryptoctx->p11 != NULL);
46707934SMark.Phalan@Sun.COM 
467111781SWill.Fiveash@Sun.COM     /* Solaris Kerberos: Login, if needed, to access private object */
467211781SWill.Fiveash@Sun.COM     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
467311781SWill.Fiveash@Sun.COM         CK_TOKEN_INFO tinfo;
467411781SWill.Fiveash@Sun.COM 
467511781SWill.Fiveash@Sun.COM         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
467611781SWill.Fiveash@Sun.COM         if (r != 0)
467711781SWill.Fiveash@Sun.COM             return r;
467811781SWill.Fiveash@Sun.COM 
467911781SWill.Fiveash@Sun.COM         r = pkinit_login(context, id_cryptoctx, &tinfo);
468011781SWill.Fiveash@Sun.COM         if (r != 0)
468111781SWill.Fiveash@Sun.COM             return r;
468211781SWill.Fiveash@Sun.COM     }
468311781SWill.Fiveash@Sun.COM 
46847934SMark.Phalan@Sun.COM     r = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
46857934SMark.Phalan@Sun.COM     if (r != 0 )
46867934SMark.Phalan@Sun.COM 	return r;
46877934SMark.Phalan@Sun.COM 
46887934SMark.Phalan@Sun.COM     mech.mechanism = id_cryptoctx->mech;
46897934SMark.Phalan@Sun.COM     mech.pParameter = NULL;
46907934SMark.Phalan@Sun.COM     mech.ulParameterLen = 0;
46917934SMark.Phalan@Sun.COM 
46927934SMark.Phalan@Sun.COM     if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
46937934SMark.Phalan@Sun.COM 	    obj)) != CKR_OK) {
46947934SMark.Phalan@Sun.COM 	pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r));
46957934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
46967934SMark.Phalan@Sun.COM     }
46977934SMark.Phalan@Sun.COM 
46987934SMark.Phalan@Sun.COM     /*
46997934SMark.Phalan@Sun.COM      * Key len would give an upper bound on sig size, but there's no way to
47007934SMark.Phalan@Sun.COM      * get that. So guess, and if it's too small, re-malloc.
47017934SMark.Phalan@Sun.COM      */
47027934SMark.Phalan@Sun.COM     len = PK_SIGLEN_GUESS;
47037934SMark.Phalan@Sun.COM     cp = (unsigned char *)malloc((size_t) len);
47047934SMark.Phalan@Sun.COM     if (cp == NULL)
47057934SMark.Phalan@Sun.COM 	return ENOMEM;
47067934SMark.Phalan@Sun.COM 
47077934SMark.Phalan@Sun.COM     r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
47087934SMark.Phalan@Sun.COM 				 (CK_ULONG) data_len, cp, &len);
47097934SMark.Phalan@Sun.COM     if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
47107934SMark.Phalan@Sun.COM 	free(cp);
47117934SMark.Phalan@Sun.COM 	pkiDebug("C_Sign realloc %d\n", (int) len);
47127934SMark.Phalan@Sun.COM 	cp = (unsigned char *)malloc((size_t) len);
47137934SMark.Phalan@Sun.COM 	r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
47147934SMark.Phalan@Sun.COM 				     (CK_ULONG) data_len, cp, &len);
47157934SMark.Phalan@Sun.COM     }
47167934SMark.Phalan@Sun.COM     if (r != CKR_OK) {
47177934SMark.Phalan@Sun.COM 	pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r));
47187934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
47197934SMark.Phalan@Sun.COM     }
47207934SMark.Phalan@Sun.COM     pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
47217934SMark.Phalan@Sun.COM     *sig_len = len;
47227934SMark.Phalan@Sun.COM     *sig = cp;
47237934SMark.Phalan@Sun.COM 
47247934SMark.Phalan@Sun.COM     return 0;
47257934SMark.Phalan@Sun.COM }
47267934SMark.Phalan@Sun.COM #endif
47277934SMark.Phalan@Sun.COM 
47287934SMark.Phalan@Sun.COM krb5_error_code
47297934SMark.Phalan@Sun.COM pkinit_sign_data(krb5_context context,
47307934SMark.Phalan@Sun.COM 		 pkinit_identity_crypto_context id_cryptoctx,
47317934SMark.Phalan@Sun.COM 		 unsigned char *data,
47327934SMark.Phalan@Sun.COM 		 unsigned int data_len,
47337934SMark.Phalan@Sun.COM 		 unsigned char **sig,
47347934SMark.Phalan@Sun.COM 		 unsigned int *sig_len)
47357934SMark.Phalan@Sun.COM {
47367934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
47377934SMark.Phalan@Sun.COM 
47387934SMark.Phalan@Sun.COM     if (id_cryptoctx == NULL || id_cryptoctx->pkcs11_method != 1)
47397934SMark.Phalan@Sun.COM 	retval = pkinit_sign_data_fs(context, id_cryptoctx, data, data_len,
47407934SMark.Phalan@Sun.COM 				     sig, sig_len);
47417934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
47427934SMark.Phalan@Sun.COM     else
47437934SMark.Phalan@Sun.COM 	retval = pkinit_sign_data_pkcs11(context, id_cryptoctx, data, data_len,
47447934SMark.Phalan@Sun.COM 					 sig, sig_len);
47457934SMark.Phalan@Sun.COM #endif
47467934SMark.Phalan@Sun.COM 
47477934SMark.Phalan@Sun.COM     return retval;
47487934SMark.Phalan@Sun.COM }
47497934SMark.Phalan@Sun.COM 
47507934SMark.Phalan@Sun.COM 
47517934SMark.Phalan@Sun.COM static krb5_error_code
47527934SMark.Phalan@Sun.COM decode_data(unsigned char **out_data, unsigned int *out_data_len,
47537934SMark.Phalan@Sun.COM 	    unsigned char *data, unsigned int data_len,
47547934SMark.Phalan@Sun.COM 	    EVP_PKEY *pkey, X509 *cert)
47557934SMark.Phalan@Sun.COM {
47567934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
47577934SMark.Phalan@Sun.COM     int len;
47587934SMark.Phalan@Sun.COM     unsigned char *buf = NULL;
47597934SMark.Phalan@Sun.COM     int buf_len = 0;
47607934SMark.Phalan@Sun.COM 
47617934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
47627934SMark.Phalan@Sun.COM     if (out_data == NULL || out_data_len == NULL)
47637934SMark.Phalan@Sun.COM 	return EINVAL;
47647934SMark.Phalan@Sun.COM 
47657934SMark.Phalan@Sun.COM     if (cert && !X509_check_private_key(cert, pkey)) {
47667934SMark.Phalan@Sun.COM 	pkiDebug("private key does not match certificate\n");
47677934SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
47687934SMark.Phalan@Sun.COM 	return EINVAL;
47697934SMark.Phalan@Sun.COM     }
47707934SMark.Phalan@Sun.COM 
47717934SMark.Phalan@Sun.COM     buf_len = EVP_PKEY_size(pkey);
47727934SMark.Phalan@Sun.COM     buf = (unsigned char *)malloc((size_t) buf_len + 10);
47737934SMark.Phalan@Sun.COM     if (buf == NULL)
47747934SMark.Phalan@Sun.COM 	return ENOMEM;
47757934SMark.Phalan@Sun.COM 
47767934SMark.Phalan@Sun.COM     len = EVP_PKEY_decrypt(buf, data, (int)data_len, pkey);
47777934SMark.Phalan@Sun.COM     if (len <= 0) {
47787934SMark.Phalan@Sun.COM 	pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
47797934SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
47807934SMark.Phalan@Sun.COM 	free(buf);
47817934SMark.Phalan@Sun.COM 	return KRB5KRB_ERR_GENERIC;
47827934SMark.Phalan@Sun.COM     }
47837934SMark.Phalan@Sun.COM     *out_data = buf;
47847934SMark.Phalan@Sun.COM     *out_data_len = len;
47857934SMark.Phalan@Sun.COM 
47867934SMark.Phalan@Sun.COM     return 0;
47877934SMark.Phalan@Sun.COM }
47887934SMark.Phalan@Sun.COM 
47897934SMark.Phalan@Sun.COM static krb5_error_code
47907934SMark.Phalan@Sun.COM create_signature(unsigned char **sig, unsigned int *sig_len,
47917934SMark.Phalan@Sun.COM 		 unsigned char *data, unsigned int data_len, EVP_PKEY *pkey)
47927934SMark.Phalan@Sun.COM {
47937934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
47947934SMark.Phalan@Sun.COM     EVP_MD_CTX md_ctx;
47957934SMark.Phalan@Sun.COM 
47967934SMark.Phalan@Sun.COM     if (pkey == NULL)
47977934SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
47987934SMark.Phalan@Sun.COM 	return EINVAL;
47997934SMark.Phalan@Sun.COM 
48007934SMark.Phalan@Sun.COM     EVP_VerifyInit(&md_ctx, EVP_sha1());
48017934SMark.Phalan@Sun.COM     EVP_SignUpdate(&md_ctx, data, data_len);
48027934SMark.Phalan@Sun.COM     *sig_len = EVP_PKEY_size(pkey);
48037934SMark.Phalan@Sun.COM     if ((*sig = (unsigned char *) malloc((size_t) *sig_len)) == NULL)
48047934SMark.Phalan@Sun.COM 	goto cleanup;
48057934SMark.Phalan@Sun.COM     EVP_SignFinal(&md_ctx, *sig, sig_len, pkey);
48067934SMark.Phalan@Sun.COM 
48077934SMark.Phalan@Sun.COM     retval = 0;
48087934SMark.Phalan@Sun.COM 
48097934SMark.Phalan@Sun.COM   cleanup:
48107934SMark.Phalan@Sun.COM     EVP_MD_CTX_cleanup(&md_ctx);
48117934SMark.Phalan@Sun.COM 
48127934SMark.Phalan@Sun.COM     return retval;
48137934SMark.Phalan@Sun.COM }
48147934SMark.Phalan@Sun.COM 
48157934SMark.Phalan@Sun.COM /*
48167934SMark.Phalan@Sun.COM  * Note:
48177934SMark.Phalan@Sun.COM  * This is not the routine the KDC uses to get its certificate.
48187934SMark.Phalan@Sun.COM  * This routine is intended to be called by the client
48197934SMark.Phalan@Sun.COM  * to obtain the KDC's certificate from some local storage
48207934SMark.Phalan@Sun.COM  * to be sent as a hint in its request to the KDC.
48217934SMark.Phalan@Sun.COM  */
48227934SMark.Phalan@Sun.COM /* ARGSUSED */
48237934SMark.Phalan@Sun.COM krb5_error_code
48247934SMark.Phalan@Sun.COM pkinit_get_kdc_cert(krb5_context context,
48257934SMark.Phalan@Sun.COM 		    pkinit_plg_crypto_context plg_cryptoctx,
48267934SMark.Phalan@Sun.COM 		    pkinit_req_crypto_context req_cryptoctx,
48277934SMark.Phalan@Sun.COM 		    pkinit_identity_crypto_context id_cryptoctx,
48287934SMark.Phalan@Sun.COM 		    krb5_principal princ)
48297934SMark.Phalan@Sun.COM {
48307934SMark.Phalan@Sun.COM    /* Solaris Kerberos */
48317934SMark.Phalan@Sun.COM     if (req_cryptoctx == NULL)
48327934SMark.Phalan@Sun.COM 	return EINVAL;
48337934SMark.Phalan@Sun.COM 
48347934SMark.Phalan@Sun.COM     req_cryptoctx->received_cert = NULL;
48357934SMark.Phalan@Sun.COM     return 0;
48367934SMark.Phalan@Sun.COM }
48377934SMark.Phalan@Sun.COM 
48387934SMark.Phalan@Sun.COM /* ARGSUSED */
48397934SMark.Phalan@Sun.COM static krb5_error_code
48407934SMark.Phalan@Sun.COM pkinit_get_certs_pkcs12(krb5_context context,
48417934SMark.Phalan@Sun.COM 			  pkinit_plg_crypto_context plg_cryptoctx,
48427934SMark.Phalan@Sun.COM 			  pkinit_req_crypto_context req_cryptoctx,
48437934SMark.Phalan@Sun.COM 			  pkinit_identity_opts *idopts,
48447934SMark.Phalan@Sun.COM 			  pkinit_identity_crypto_context id_cryptoctx,
48457934SMark.Phalan@Sun.COM 			  krb5_principal princ)
48467934SMark.Phalan@Sun.COM {
48477934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
48487934SMark.Phalan@Sun.COM     X509 *x = NULL;
48497934SMark.Phalan@Sun.COM     PKCS12 *p12 = NULL;
48507934SMark.Phalan@Sun.COM     int ret;
48517934SMark.Phalan@Sun.COM     FILE *fp;
48527934SMark.Phalan@Sun.COM     EVP_PKEY *y = NULL;
48537934SMark.Phalan@Sun.COM 
48547934SMark.Phalan@Sun.COM     if (idopts->cert_filename == NULL) {
48557934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Improved error messages */
48567934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval,
4857*12945Swill.fiveash@oracle.com 	    gettext("Failed to get certificate location"));
48587934SMark.Phalan@Sun.COM 	pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
48597934SMark.Phalan@Sun.COM 	goto cleanup;
48607934SMark.Phalan@Sun.COM     }
48617934SMark.Phalan@Sun.COM 
48627934SMark.Phalan@Sun.COM     if (idopts->key_filename == NULL) {
48637934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Improved error messages */
48647934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval,
4865*12945Swill.fiveash@oracle.com 	    gettext("Failed to get private key location"));
48667934SMark.Phalan@Sun.COM 	pkiDebug("%s: failed to get user's private key location\n", __FUNCTION__);
48677934SMark.Phalan@Sun.COM 	goto cleanup;
48687934SMark.Phalan@Sun.COM     }
48697934SMark.Phalan@Sun.COM 
48707934SMark.Phalan@Sun.COM     fp = fopen(idopts->cert_filename, "rb");
48717934SMark.Phalan@Sun.COM     if (fp == NULL) {
48727934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Improved error messages */
48737934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval,
4874*12945Swill.fiveash@oracle.com 	    gettext("Failed to open PKCS12 file '%s': %s"),
48757934SMark.Phalan@Sun.COM 	    idopts->cert_filename, error_message(errno));
48767934SMark.Phalan@Sun.COM 	pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
48777934SMark.Phalan@Sun.COM 		 idopts->cert_filename, errno);
48787934SMark.Phalan@Sun.COM 	goto cleanup;
48797934SMark.Phalan@Sun.COM     }
48807934SMark.Phalan@Sun.COM 
48817934SMark.Phalan@Sun.COM     p12 = d2i_PKCS12_fp(fp, NULL);
48827934SMark.Phalan@Sun.COM     (void) fclose(fp);
48837934SMark.Phalan@Sun.COM     if (p12 == NULL) {
48847934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval,
4885*12945Swill.fiveash@oracle.com 	    gettext("Failed to decode PKCS12 file '%s' contents"),
48867934SMark.Phalan@Sun.COM 	    idopts->cert_filename);
48877934SMark.Phalan@Sun.COM 	pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
48887934SMark.Phalan@Sun.COM 		 idopts->cert_filename);
48897934SMark.Phalan@Sun.COM 	goto cleanup;
48907934SMark.Phalan@Sun.COM     }
48917934SMark.Phalan@Sun.COM     /*
48927934SMark.Phalan@Sun.COM      * Try parsing with no pass phrase first.  If that fails,
48937934SMark.Phalan@Sun.COM      * prompt for the pass phrase and try again.
48947934SMark.Phalan@Sun.COM      */
48957934SMark.Phalan@Sun.COM     ret = PKCS12_parse(p12, NULL, &y, &x, NULL);
48967934SMark.Phalan@Sun.COM     if (ret == 0) {
48977934SMark.Phalan@Sun.COM 	krb5_data rdat;
48987934SMark.Phalan@Sun.COM 	krb5_prompt kprompt;
48997934SMark.Phalan@Sun.COM 	krb5_prompt_type prompt_type;
49007934SMark.Phalan@Sun.COM 	int r = 0;
49017934SMark.Phalan@Sun.COM 	char prompt_string[128];
49027934SMark.Phalan@Sun.COM 	char prompt_reply[128];
49037934SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
49047934SMark.Phalan@Sun.COM 	char *prompt_prefix = gettext("Pass phrase for");
49057934SMark.Phalan@Sun.COM 
49067934SMark.Phalan@Sun.COM 	pkiDebug("Initial PKCS12_parse with no password failed\n");
49077934SMark.Phalan@Sun.COM 
490812941Swill.fiveash@oracle.com 	if (id_cryptoctx->PIN != NULL) {
490912941Swill.fiveash@oracle.com 		/* Solaris Kerberos: use PIN if set */
491012941Swill.fiveash@oracle.com 		rdat.data = id_cryptoctx->PIN;
491112941Swill.fiveash@oracle.com 		/* note rdat.length isn't needed in this case */
491212941Swill.fiveash@oracle.com 	} else {
491312941Swill.fiveash@oracle.com 		(void) memset(prompt_reply, '\0', sizeof(prompt_reply));
491412941Swill.fiveash@oracle.com 		rdat.data = prompt_reply;
491512941Swill.fiveash@oracle.com 		rdat.length = sizeof(prompt_reply);
491612941Swill.fiveash@oracle.com 
491712941Swill.fiveash@oracle.com 		r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
491812941Swill.fiveash@oracle.com 			     prompt_prefix, idopts->cert_filename);
491912941Swill.fiveash@oracle.com 		if (r >= sizeof(prompt_string)) {
492012941Swill.fiveash@oracle.com 		    pkiDebug("Prompt string, '%s %s', is too long!\n",
492112941Swill.fiveash@oracle.com 			     prompt_prefix, idopts->cert_filename);
492212941Swill.fiveash@oracle.com 		    goto cleanup;
492312941Swill.fiveash@oracle.com 		}
492412941Swill.fiveash@oracle.com 		kprompt.prompt = prompt_string;
492512941Swill.fiveash@oracle.com 		kprompt.hidden = 1;
492612941Swill.fiveash@oracle.com 		kprompt.reply = &rdat;
492712941Swill.fiveash@oracle.com 		prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
492812941Swill.fiveash@oracle.com 
492912941Swill.fiveash@oracle.com 		/* PROMPTER_INVOCATION */
493012941Swill.fiveash@oracle.com 		k5int_set_prompt_types(context, &prompt_type);
493112941Swill.fiveash@oracle.com 		r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
493212941Swill.fiveash@oracle.com 					      NULL, NULL, 1, &kprompt);
493312941Swill.fiveash@oracle.com 		k5int_set_prompt_types(context, NULL);
49347934SMark.Phalan@Sun.COM 	}
49357934SMark.Phalan@Sun.COM 
49367934SMark.Phalan@Sun.COM 	ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
49377934SMark.Phalan@Sun.COM 	if (ret == 0) {
49387934SMark.Phalan@Sun.COM 	    /* Solaris Kerberos: Improved error messages */
49397934SMark.Phalan@Sun.COM 	    krb5_set_error_message(context, retval,
4940*12945Swill.fiveash@oracle.com 	        gettext("Failed to parse PKCS12 file '%s' with password"),
49417934SMark.Phalan@Sun.COM 	        idopts->cert_filename);
49427934SMark.Phalan@Sun.COM 	    pkiDebug("Seconde PKCS12_parse with password failed\n");
49437934SMark.Phalan@Sun.COM 	    goto cleanup;
49447934SMark.Phalan@Sun.COM 	}
49457934SMark.Phalan@Sun.COM     }
49467934SMark.Phalan@Sun.COM     id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
49477934SMark.Phalan@Sun.COM     if (id_cryptoctx->creds[0] == NULL)
49487934SMark.Phalan@Sun.COM 	goto cleanup;
49497934SMark.Phalan@Sun.COM     id_cryptoctx->creds[0]->cert = x;
49507934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
49517934SMark.Phalan@Sun.COM     id_cryptoctx->creds[0]->cert_id = NULL;
49527934SMark.Phalan@Sun.COM     id_cryptoctx->creds[0]->cert_id_len = 0;
49537934SMark.Phalan@Sun.COM #endif
49547934SMark.Phalan@Sun.COM     id_cryptoctx->creds[0]->key = y;
49557934SMark.Phalan@Sun.COM     id_cryptoctx->creds[1] = NULL;
49567934SMark.Phalan@Sun.COM 
49577934SMark.Phalan@Sun.COM     retval = 0;
49587934SMark.Phalan@Sun.COM 
49597934SMark.Phalan@Sun.COM cleanup:
49607934SMark.Phalan@Sun.COM     if (p12)
49617934SMark.Phalan@Sun.COM 	PKCS12_free(p12);
49627934SMark.Phalan@Sun.COM     if (retval) {
49637934SMark.Phalan@Sun.COM 	if (x != NULL)
49647934SMark.Phalan@Sun.COM 	    X509_free(x);
49657934SMark.Phalan@Sun.COM 	if (y != NULL)
49667934SMark.Phalan@Sun.COM 	    EVP_PKEY_free(y);
49677934SMark.Phalan@Sun.COM     }
49687934SMark.Phalan@Sun.COM     return retval;
49697934SMark.Phalan@Sun.COM }
49707934SMark.Phalan@Sun.COM 
49717934SMark.Phalan@Sun.COM static krb5_error_code
49727934SMark.Phalan@Sun.COM pkinit_load_fs_cert_and_key(krb5_context context,
49737934SMark.Phalan@Sun.COM 			    pkinit_identity_crypto_context id_cryptoctx,
49747934SMark.Phalan@Sun.COM 			    char *certname,
49757934SMark.Phalan@Sun.COM 			    char *keyname,
49767934SMark.Phalan@Sun.COM 			    int cindex)
49777934SMark.Phalan@Sun.COM {
49787934SMark.Phalan@Sun.COM     krb5_error_code retval;
49797934SMark.Phalan@Sun.COM     X509 *x = NULL;
49807934SMark.Phalan@Sun.COM     EVP_PKEY *y = NULL;
49817934SMark.Phalan@Sun.COM 
49827934SMark.Phalan@Sun.COM     /* load the certificate */
49837934SMark.Phalan@Sun.COM     retval = get_cert(certname, &x);
49847934SMark.Phalan@Sun.COM     if (retval != 0 || x == NULL) {
49857934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Improved error messages */
49867934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval,
4987*12945Swill.fiveash@oracle.com 	    gettext("Failed to load user's certificate from %s: %s"),
49887934SMark.Phalan@Sun.COM 	        certname, error_message(retval));
49897934SMark.Phalan@Sun.COM 	pkiDebug("failed to load user's certificate from '%s'\n", certname);
49907934SMark.Phalan@Sun.COM 	goto cleanup;
49917934SMark.Phalan@Sun.COM     }
49927934SMark.Phalan@Sun.COM     retval = get_key(keyname, &y);
49937934SMark.Phalan@Sun.COM     if (retval != 0 || y == NULL) {
49947934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Improved error messages */
49957934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval,
4996*12945Swill.fiveash@oracle.com 	    gettext("Failed to load user's private key from %s: %s"),
49977934SMark.Phalan@Sun.COM 	        keyname, error_message(retval));
49987934SMark.Phalan@Sun.COM 	pkiDebug("failed to load user's private key from '%s'\n", keyname);
49997934SMark.Phalan@Sun.COM 	goto cleanup;
50007934SMark.Phalan@Sun.COM     }
50017934SMark.Phalan@Sun.COM 
50027934SMark.Phalan@Sun.COM     id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
50037934SMark.Phalan@Sun.COM     if (id_cryptoctx->creds[cindex] == NULL) {
50047934SMark.Phalan@Sun.COM 	retval = ENOMEM;
50057934SMark.Phalan@Sun.COM 	goto cleanup;
50067934SMark.Phalan@Sun.COM     }
50077934SMark.Phalan@Sun.COM     id_cryptoctx->creds[cindex]->cert = x;
50087934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
50097934SMark.Phalan@Sun.COM     id_cryptoctx->creds[cindex]->cert_id = NULL;
50107934SMark.Phalan@Sun.COM     id_cryptoctx->creds[cindex]->cert_id_len = 0;
50117934SMark.Phalan@Sun.COM #endif
50127934SMark.Phalan@Sun.COM     id_cryptoctx->creds[cindex]->key = y;
50137934SMark.Phalan@Sun.COM     id_cryptoctx->creds[cindex+1] = NULL;
50147934SMark.Phalan@Sun.COM 
50157934SMark.Phalan@Sun.COM     retval = 0;
50167934SMark.Phalan@Sun.COM 
50177934SMark.Phalan@Sun.COM cleanup:
50187934SMark.Phalan@Sun.COM     if (retval) {
50197934SMark.Phalan@Sun.COM 	if (x != NULL)
50207934SMark.Phalan@Sun.COM 	    X509_free(x);
50217934SMark.Phalan@Sun.COM 	if (y != NULL)
50227934SMark.Phalan@Sun.COM 	    EVP_PKEY_free(y);
50237934SMark.Phalan@Sun.COM     }
50247934SMark.Phalan@Sun.COM     return retval;
50257934SMark.Phalan@Sun.COM }
50267934SMark.Phalan@Sun.COM 
50277934SMark.Phalan@Sun.COM /* ARGSUSED */
50287934SMark.Phalan@Sun.COM static krb5_error_code
50297934SMark.Phalan@Sun.COM pkinit_get_certs_fs(krb5_context context,
50307934SMark.Phalan@Sun.COM 			  pkinit_plg_crypto_context plg_cryptoctx,
50317934SMark.Phalan@Sun.COM 			  pkinit_req_crypto_context req_cryptoctx,
50327934SMark.Phalan@Sun.COM 			  pkinit_identity_opts *idopts,
50337934SMark.Phalan@Sun.COM 			  pkinit_identity_crypto_context id_cryptoctx,
50347934SMark.Phalan@Sun.COM 			  krb5_principal princ)
50357934SMark.Phalan@Sun.COM {
50367934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
50377934SMark.Phalan@Sun.COM 
50387934SMark.Phalan@Sun.COM     if (idopts->cert_filename == NULL) {
50397934SMark.Phalan@Sun.COM 	pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
50407934SMark.Phalan@Sun.COM 	goto cleanup;
50417934SMark.Phalan@Sun.COM     }
50427934SMark.Phalan@Sun.COM 
50437934SMark.Phalan@Sun.COM     if (idopts->key_filename == NULL) {
50447934SMark.Phalan@Sun.COM 	pkiDebug("%s: failed to get user's private key location\n",
50457934SMark.Phalan@Sun.COM 		 __FUNCTION__);
50467934SMark.Phalan@Sun.COM 	goto cleanup;
50477934SMark.Phalan@Sun.COM     }
50487934SMark.Phalan@Sun.COM 
50497934SMark.Phalan@Sun.COM     retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
50507934SMark.Phalan@Sun.COM 					 idopts->cert_filename,
50517934SMark.Phalan@Sun.COM 					 idopts->key_filename, 0);
50527934SMark.Phalan@Sun.COM cleanup:
50537934SMark.Phalan@Sun.COM     return retval;
50547934SMark.Phalan@Sun.COM }
50557934SMark.Phalan@Sun.COM 
50567934SMark.Phalan@Sun.COM /* ARGSUSED */
50577934SMark.Phalan@Sun.COM static krb5_error_code
50587934SMark.Phalan@Sun.COM pkinit_get_certs_dir(krb5_context context,
50597934SMark.Phalan@Sun.COM 		     pkinit_plg_crypto_context plg_cryptoctx,
50607934SMark.Phalan@Sun.COM 		     pkinit_req_crypto_context req_cryptoctx,
50617934SMark.Phalan@Sun.COM 		     pkinit_identity_opts *idopts,
50627934SMark.Phalan@Sun.COM 		     pkinit_identity_crypto_context id_cryptoctx,
50637934SMark.Phalan@Sun.COM 		     krb5_principal princ)
50647934SMark.Phalan@Sun.COM {
50657934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
50667934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
50677934SMark.Phalan@Sun.COM     DIR *d = NULL;
50687934SMark.Phalan@Sun.COM     struct dirent *dentry = NULL;
50697934SMark.Phalan@Sun.COM     char certname[1024];
50707934SMark.Phalan@Sun.COM     char keyname[1024];
50717934SMark.Phalan@Sun.COM     int i = 0, len;
50727934SMark.Phalan@Sun.COM     char *dirname, *suf;
50737934SMark.Phalan@Sun.COM 
50747934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
50757934SMark.Phalan@Sun.COM     if (idopts == NULL)
50767934SMark.Phalan@Sun.COM 	return EINVAL;
50777934SMark.Phalan@Sun.COM 
50787934SMark.Phalan@Sun.COM     if (idopts->cert_filename == NULL) {
50797934SMark.Phalan@Sun.COM 	pkiDebug("%s: failed to get user's certificate directory location\n",
50807934SMark.Phalan@Sun.COM 		 __FUNCTION__);
50817934SMark.Phalan@Sun.COM 	return ENOENT;
50827934SMark.Phalan@Sun.COM     }
50837934SMark.Phalan@Sun.COM 
50847934SMark.Phalan@Sun.COM     dirname = idopts->cert_filename;
50857934SMark.Phalan@Sun.COM     d = opendir(dirname);
50867934SMark.Phalan@Sun.COM     if (d == NULL) {
50877934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Improved error messages */
50887934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, errno,
5089*12945Swill.fiveash@oracle.com 	    gettext("Failed to open directory \"%s\": %s"),
50907934SMark.Phalan@Sun.COM 	    dirname, error_message(errno));
50917934SMark.Phalan@Sun.COM 	return errno;
50927934SMark.Phalan@Sun.COM     }
50937934SMark.Phalan@Sun.COM 
50947934SMark.Phalan@Sun.COM     /*
50957934SMark.Phalan@Sun.COM      * We'll assume that certs are named XXX.crt and the corresponding
50967934SMark.Phalan@Sun.COM      * key is named XXX.key
50977934SMark.Phalan@Sun.COM      */
50987934SMark.Phalan@Sun.COM     while ((i < MAX_CREDS_ALLOWED) &&  (dentry = readdir(d)) != NULL) {
50997934SMark.Phalan@Sun.COM 	/* Ignore subdirectories and anything starting with a dot */
51007934SMark.Phalan@Sun.COM #ifdef DT_DIR
51017934SMark.Phalan@Sun.COM 	if (dentry->d_type == DT_DIR)
51027934SMark.Phalan@Sun.COM 	    continue;
51037934SMark.Phalan@Sun.COM #endif
51047934SMark.Phalan@Sun.COM 	if (dentry->d_name[0] == '.')
51057934SMark.Phalan@Sun.COM 	    continue;
51067934SMark.Phalan@Sun.COM 	len = strlen(dentry->d_name);
51077934SMark.Phalan@Sun.COM 	if (len < 5)
51087934SMark.Phalan@Sun.COM 	    continue;
51097934SMark.Phalan@Sun.COM 	suf = dentry->d_name + (len - 4);
51107934SMark.Phalan@Sun.COM 	if (strncmp(suf, ".crt", 4) != 0)
51117934SMark.Phalan@Sun.COM 	    continue;
51127934SMark.Phalan@Sun.COM 
51137934SMark.Phalan@Sun.COM 	/* Checked length */
51147934SMark.Phalan@Sun.COM 	if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(certname)) {
51157934SMark.Phalan@Sun.COM 	    pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
51167934SMark.Phalan@Sun.COM 		     __FUNCTION__, dirname, dentry->d_name);
51177934SMark.Phalan@Sun.COM 	    continue;
51187934SMark.Phalan@Sun.COM 	}
51197934SMark.Phalan@Sun.COM 	(void) snprintf(certname, sizeof(certname), "%s/%s", dirname, dentry->d_name);
51207934SMark.Phalan@Sun.COM 	(void) snprintf(keyname, sizeof(keyname), "%s/%s", dirname, dentry->d_name);
51217934SMark.Phalan@Sun.COM 	len = strlen(keyname);
51227934SMark.Phalan@Sun.COM 	keyname[len - 3] = 'k';
51237934SMark.Phalan@Sun.COM 	keyname[len - 2] = 'e';
51247934SMark.Phalan@Sun.COM 	keyname[len - 1] = 'y';
51257934SMark.Phalan@Sun.COM 
51267934SMark.Phalan@Sun.COM 	retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
51277934SMark.Phalan@Sun.COM 					     certname, keyname, i);
51287934SMark.Phalan@Sun.COM 	if (retval == 0) {
51297934SMark.Phalan@Sun.COM 	    pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
51307934SMark.Phalan@Sun.COM 		     __FUNCTION__, dentry->d_name);
51317934SMark.Phalan@Sun.COM 	    i++;
51327934SMark.Phalan@Sun.COM 	}
51337934SMark.Phalan@Sun.COM 	else
51347934SMark.Phalan@Sun.COM 	    continue;
51357934SMark.Phalan@Sun.COM     }
51367934SMark.Phalan@Sun.COM 
51377934SMark.Phalan@Sun.COM     if (i == 0) {
51387934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Improved error messages */
51397934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, ENOENT,
51407934SMark.Phalan@Sun.COM 	    gettext("No suitable cert/key pairs found in directory '%s'"),
51417934SMark.Phalan@Sun.COM 	    idopts->cert_filename);
51427934SMark.Phalan@Sun.COM 	pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
51437934SMark.Phalan@Sun.COM 		 __FUNCTION__, idopts->cert_filename);
51447934SMark.Phalan@Sun.COM 	retval = ENOENT;
51457934SMark.Phalan@Sun.COM 	goto cleanup;
51467934SMark.Phalan@Sun.COM     }
51477934SMark.Phalan@Sun.COM 
51487934SMark.Phalan@Sun.COM     retval = 0;
51497934SMark.Phalan@Sun.COM 
51507934SMark.Phalan@Sun.COM   cleanup:
51517934SMark.Phalan@Sun.COM     if (d)
51527934SMark.Phalan@Sun.COM 	(void) closedir(d);
51537934SMark.Phalan@Sun.COM 
51547934SMark.Phalan@Sun.COM     return retval;
51557934SMark.Phalan@Sun.COM }
51567934SMark.Phalan@Sun.COM 
51577934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
51587934SMark.Phalan@Sun.COM /* ARGSUSED */
51597934SMark.Phalan@Sun.COM static krb5_error_code
51607934SMark.Phalan@Sun.COM pkinit_get_certs_pkcs11(krb5_context context,
51617934SMark.Phalan@Sun.COM 			pkinit_plg_crypto_context plg_cryptoctx,
51627934SMark.Phalan@Sun.COM 			pkinit_req_crypto_context req_cryptoctx,
51637934SMark.Phalan@Sun.COM 			pkinit_identity_opts *idopts,
51647934SMark.Phalan@Sun.COM 			pkinit_identity_crypto_context id_cryptoctx,
5165*12945Swill.fiveash@oracle.com 			krb5_principal princ,
5166*12945Swill.fiveash@oracle.com 			int do_matching)
51677934SMark.Phalan@Sun.COM {
51687934SMark.Phalan@Sun.COM #ifdef PKINIT_USE_MECH_LIST
5169*12945Swill.fiveash@oracle.com     CK_MECHANISM_TYPE_PTR mechp = NULL;
51707934SMark.Phalan@Sun.COM     CK_MECHANISM_INFO info;
51717934SMark.Phalan@Sun.COM #endif
5172*12945Swill.fiveash@oracle.com 
5173*12945Swill.fiveash@oracle.com     if (id_cryptoctx->p11flags & C_SKIP_PKCS11_AUTH)
5174*12945Swill.fiveash@oracle.com 	return KRB5KDC_ERR_PREAUTH_FAILED;
51757934SMark.Phalan@Sun.COM 
51767934SMark.Phalan@Sun.COM     /* Copy stuff from idopts -> id_cryptoctx */
51777934SMark.Phalan@Sun.COM     if (idopts->p11_module_name != NULL) {
51787934SMark.Phalan@Sun.COM 	id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
51797934SMark.Phalan@Sun.COM 	if (id_cryptoctx->p11_module_name == NULL)
51807934SMark.Phalan@Sun.COM 	    return ENOMEM;
51817934SMark.Phalan@Sun.COM     }
51827934SMark.Phalan@Sun.COM     if (idopts->token_label != NULL) {
51837934SMark.Phalan@Sun.COM 	id_cryptoctx->token_label = strdup(idopts->token_label);
51847934SMark.Phalan@Sun.COM 	if (id_cryptoctx->token_label == NULL)
51857934SMark.Phalan@Sun.COM 	    return ENOMEM;
51867934SMark.Phalan@Sun.COM     }
51877934SMark.Phalan@Sun.COM     if (idopts->cert_label != NULL) {
51887934SMark.Phalan@Sun.COM 	id_cryptoctx->cert_label = strdup(idopts->cert_label);
51897934SMark.Phalan@Sun.COM 	if (id_cryptoctx->cert_label == NULL)
51907934SMark.Phalan@Sun.COM 	    return ENOMEM;
51917934SMark.Phalan@Sun.COM     }
519212941Swill.fiveash@oracle.com     if (idopts->PIN != NULL) {
519312941Swill.fiveash@oracle.com 	id_cryptoctx->PIN = strdup(idopts->PIN);
519412941Swill.fiveash@oracle.com 	if (id_cryptoctx->PIN == NULL)
519512941Swill.fiveash@oracle.com 	    return ENOMEM;
519612941Swill.fiveash@oracle.com     }
51977934SMark.Phalan@Sun.COM     /* Convert the ascii cert_id string into a binary blob */
51987934SMark.Phalan@Sun.COM     /*
51997934SMark.Phalan@Sun.COM      * Solaris Kerberos:
52007934SMark.Phalan@Sun.COM      * If the cert_id_string is empty then behave in a similar way to how
52017934SMark.Phalan@Sun.COM      * an empty certlabel is treated - i.e. don't fail now but rather continue
52027934SMark.Phalan@Sun.COM      * as though the certid wasn't specified.
52037934SMark.Phalan@Sun.COM      */
52047934SMark.Phalan@Sun.COM     if (idopts->cert_id_string != NULL && strlen(idopts->cert_id_string) != 0) {
52057934SMark.Phalan@Sun.COM 	BIGNUM *bn = NULL;
52067934SMark.Phalan@Sun.COM 	BN_hex2bn(&bn, idopts->cert_id_string);
52077934SMark.Phalan@Sun.COM 	if (bn == NULL)
52087934SMark.Phalan@Sun.COM 	    return ENOMEM;
52097934SMark.Phalan@Sun.COM 	id_cryptoctx->cert_id_len = BN_num_bytes(bn);
52107934SMark.Phalan@Sun.COM 	id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
52117934SMark.Phalan@Sun.COM 	if (id_cryptoctx->cert_id == NULL) {
52127934SMark.Phalan@Sun.COM 	    BN_free(bn);
52137934SMark.Phalan@Sun.COM 	    return ENOMEM;
52147934SMark.Phalan@Sun.COM 	}
52157934SMark.Phalan@Sun.COM 	BN_bn2bin(bn, id_cryptoctx->cert_id);
52167934SMark.Phalan@Sun.COM 	BN_free(bn);
52177934SMark.Phalan@Sun.COM     }
52187934SMark.Phalan@Sun.COM     id_cryptoctx->slotid = idopts->slotid;
52197934SMark.Phalan@Sun.COM     id_cryptoctx->pkcs11_method = 1;
52207934SMark.Phalan@Sun.COM 
52217934SMark.Phalan@Sun.COM #ifndef PKINIT_USE_MECH_LIST
52227934SMark.Phalan@Sun.COM     /*
52237934SMark.Phalan@Sun.COM      * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
52247934SMark.Phalan@Sun.COM      * many cards seems to be confused about whether they are capable of
52257934SMark.Phalan@Sun.COM      * this or not. The safe thing seems to be to ignore the mechanism list,
52267934SMark.Phalan@Sun.COM      * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
52277934SMark.Phalan@Sun.COM      */
52287934SMark.Phalan@Sun.COM 
52297934SMark.Phalan@Sun.COM     id_cryptoctx->mech = CKM_RSA_PKCS;
52307934SMark.Phalan@Sun.COM #else
52317934SMark.Phalan@Sun.COM     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL,
52327934SMark.Phalan@Sun.COM 	    &count)) != CKR_OK || count <= 0) {
52337934SMark.Phalan@Sun.COM 	pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r));
52347934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
52357934SMark.Phalan@Sun.COM     }
52367934SMark.Phalan@Sun.COM     mechp = (CK_MECHANISM_TYPE_PTR) malloc(count * sizeof (CK_MECHANISM_TYPE));
52377934SMark.Phalan@Sun.COM     if (mechp == NULL)
52387934SMark.Phalan@Sun.COM 	return ENOMEM;
52397934SMark.Phalan@Sun.COM     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid,
5240*12945Swill.fiveash@oracle.com 	    mechp, &count)) != CKR_OK) {
5241*12945Swill.fiveash@oracle.com 	free(mechp);
52427934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
5243*12945Swill.fiveash@oracle.com     }
52447934SMark.Phalan@Sun.COM     for (i = 0; i < count; i++) {
52457934SMark.Phalan@Sun.COM 	if ((r = id_cryptoctx->p11->C_GetMechanismInfo(id_cryptoctx->slotid,
5246*12945Swill.fiveash@oracle.com 		mechp[i], &info)) != CKR_OK) {
5247*12945Swill.fiveash@oracle.com 	    free(mechp);
52487934SMark.Phalan@Sun.COM 	    return KRB5KDC_ERR_PREAUTH_FAILED;
5249*12945Swill.fiveash@oracle.com 	}
52507934SMark.Phalan@Sun.COM #ifdef DEBUG_MECHINFO
52517934SMark.Phalan@Sun.COM 	pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
52527934SMark.Phalan@Sun.COM 	if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
52537934SMark.Phalan@Sun.COM 	    pkiDebug("  this mech is good for sign & decrypt\n");
52547934SMark.Phalan@Sun.COM #endif
52557934SMark.Phalan@Sun.COM 	if (mechp[i] == CKM_RSA_PKCS) {
52567934SMark.Phalan@Sun.COM 	    /* This seems backwards... */
52577934SMark.Phalan@Sun.COM 	    id_cryptoctx->mech =
52587934SMark.Phalan@Sun.COM 		(info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
52597934SMark.Phalan@Sun.COM 	}
52607934SMark.Phalan@Sun.COM     }
52617934SMark.Phalan@Sun.COM     free(mechp);
52627934SMark.Phalan@Sun.COM 
52637934SMark.Phalan@Sun.COM     pkiDebug("got %d mechs from card\n", (int) count);
52647934SMark.Phalan@Sun.COM #endif
52657934SMark.Phalan@Sun.COM 
5266*12945Swill.fiveash@oracle.com     return (pkinit_open_session(context, plg_cryptoctx, req_cryptoctx,
5267*12945Swill.fiveash@oracle.com                                 id_cryptoctx, princ, do_matching));
52687934SMark.Phalan@Sun.COM }
52697934SMark.Phalan@Sun.COM #endif
52707934SMark.Phalan@Sun.COM 
52717934SMark.Phalan@Sun.COM /* ARGSUSED */
52727934SMark.Phalan@Sun.COM static void
52737934SMark.Phalan@Sun.COM free_cred_info(krb5_context context,
52747934SMark.Phalan@Sun.COM 	       pkinit_identity_crypto_context id_cryptoctx,
52757934SMark.Phalan@Sun.COM 	       struct _pkinit_cred_info *cred)
52767934SMark.Phalan@Sun.COM {
52777934SMark.Phalan@Sun.COM     if (cred != NULL) {
52787934SMark.Phalan@Sun.COM 	if (cred->cert != NULL)
52797934SMark.Phalan@Sun.COM 	    X509_free(cred->cert);
52807934SMark.Phalan@Sun.COM 	if (cred->key != NULL)
52817934SMark.Phalan@Sun.COM 	    EVP_PKEY_free(cred->key);
52827934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
52837934SMark.Phalan@Sun.COM 	if (cred->cert_id != NULL)
52847934SMark.Phalan@Sun.COM 	    free(cred->cert_id);
52857934SMark.Phalan@Sun.COM #endif
52867934SMark.Phalan@Sun.COM 	free(cred);
52877934SMark.Phalan@Sun.COM     }
52887934SMark.Phalan@Sun.COM }
52897934SMark.Phalan@Sun.COM 
52907934SMark.Phalan@Sun.COM /* ARGSUSED */
52917934SMark.Phalan@Sun.COM krb5_error_code
52927934SMark.Phalan@Sun.COM crypto_free_cert_info(krb5_context context,
52937934SMark.Phalan@Sun.COM 		      pkinit_plg_crypto_context plg_cryptoctx,
52947934SMark.Phalan@Sun.COM 		      pkinit_req_crypto_context req_cryptoctx,
52957934SMark.Phalan@Sun.COM 		      pkinit_identity_crypto_context id_cryptoctx)
52967934SMark.Phalan@Sun.COM {
52977934SMark.Phalan@Sun.COM     int i;
52987934SMark.Phalan@Sun.COM 
52997934SMark.Phalan@Sun.COM     if (id_cryptoctx == NULL)
53007934SMark.Phalan@Sun.COM 	return EINVAL;
53017934SMark.Phalan@Sun.COM 
53027934SMark.Phalan@Sun.COM     for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
53037934SMark.Phalan@Sun.COM 	if (id_cryptoctx->creds[i] != NULL) {
53047934SMark.Phalan@Sun.COM 	    free_cred_info(context, id_cryptoctx, id_cryptoctx->creds[i]);
53057934SMark.Phalan@Sun.COM 	    id_cryptoctx->creds[i] = NULL;
53067934SMark.Phalan@Sun.COM 	}
53077934SMark.Phalan@Sun.COM     }
53087934SMark.Phalan@Sun.COM     return 0;
53097934SMark.Phalan@Sun.COM }
53107934SMark.Phalan@Sun.COM 
53117934SMark.Phalan@Sun.COM krb5_error_code
53127934SMark.Phalan@Sun.COM crypto_load_certs(krb5_context context,
53137934SMark.Phalan@Sun.COM 		  pkinit_plg_crypto_context plg_cryptoctx,
53147934SMark.Phalan@Sun.COM 		  pkinit_req_crypto_context req_cryptoctx,
53157934SMark.Phalan@Sun.COM 		  pkinit_identity_opts *idopts,
53167934SMark.Phalan@Sun.COM 		  pkinit_identity_crypto_context id_cryptoctx,
5317*12945Swill.fiveash@oracle.com 		  krb5_principal princ,
5318*12945Swill.fiveash@oracle.com 		  int do_matching)
53197934SMark.Phalan@Sun.COM {
53207934SMark.Phalan@Sun.COM     krb5_error_code retval;
53217934SMark.Phalan@Sun.COM 
53227934SMark.Phalan@Sun.COM     switch(idopts->idtype) {
53237934SMark.Phalan@Sun.COM 	case IDTYPE_FILE:
53247934SMark.Phalan@Sun.COM 	    retval = pkinit_get_certs_fs(context, plg_cryptoctx,
53257934SMark.Phalan@Sun.COM 					 req_cryptoctx, idopts,
53267934SMark.Phalan@Sun.COM 					 id_cryptoctx, princ);
53277934SMark.Phalan@Sun.COM 	    break;
53287934SMark.Phalan@Sun.COM 	case IDTYPE_DIR:
53297934SMark.Phalan@Sun.COM 	    retval = pkinit_get_certs_dir(context, plg_cryptoctx,
53307934SMark.Phalan@Sun.COM 					  req_cryptoctx, idopts,
53317934SMark.Phalan@Sun.COM 					  id_cryptoctx, princ);
53327934SMark.Phalan@Sun.COM 	    break;
53337934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
53347934SMark.Phalan@Sun.COM 	case IDTYPE_PKCS11:
53357934SMark.Phalan@Sun.COM 	    retval = pkinit_get_certs_pkcs11(context, plg_cryptoctx,
53367934SMark.Phalan@Sun.COM 					     req_cryptoctx, idopts,
5337*12945Swill.fiveash@oracle.com 					     id_cryptoctx, princ, do_matching);
53387934SMark.Phalan@Sun.COM 	    break;
53397934SMark.Phalan@Sun.COM #endif
53407934SMark.Phalan@Sun.COM 	case IDTYPE_PKCS12:
53417934SMark.Phalan@Sun.COM 	    retval = pkinit_get_certs_pkcs12(context, plg_cryptoctx,
53427934SMark.Phalan@Sun.COM 					     req_cryptoctx, idopts,
53437934SMark.Phalan@Sun.COM 					     id_cryptoctx, princ);
53447934SMark.Phalan@Sun.COM 		break;
53457934SMark.Phalan@Sun.COM 	default:
53467934SMark.Phalan@Sun.COM 	    retval = EINVAL;
53477934SMark.Phalan@Sun.COM     }
53487934SMark.Phalan@Sun.COM /* Solaris Kerberos */
53497934SMark.Phalan@Sun.COM 
53507934SMark.Phalan@Sun.COM     return retval;
53517934SMark.Phalan@Sun.COM }
53527934SMark.Phalan@Sun.COM 
53537934SMark.Phalan@Sun.COM /*
53547934SMark.Phalan@Sun.COM  * Get number of certificates available after crypto_load_certs()
53557934SMark.Phalan@Sun.COM  */
53567934SMark.Phalan@Sun.COM /* ARGSUSED */
53577934SMark.Phalan@Sun.COM krb5_error_code
53587934SMark.Phalan@Sun.COM crypto_cert_get_count(krb5_context context,
53597934SMark.Phalan@Sun.COM 		      pkinit_plg_crypto_context plg_cryptoctx,
53607934SMark.Phalan@Sun.COM 		      pkinit_req_crypto_context req_cryptoctx,
53617934SMark.Phalan@Sun.COM 		      pkinit_identity_crypto_context id_cryptoctx,
53627934SMark.Phalan@Sun.COM 		      int *cert_count)
53637934SMark.Phalan@Sun.COM {
53647934SMark.Phalan@Sun.COM     int count;
53657934SMark.Phalan@Sun.COM 
53667934SMark.Phalan@Sun.COM     if (id_cryptoctx == NULL || id_cryptoctx->creds[0] == NULL)
53677934SMark.Phalan@Sun.COM 	return EINVAL;
53687934SMark.Phalan@Sun.COM 
53697934SMark.Phalan@Sun.COM     for (count = 0;
53707934SMark.Phalan@Sun.COM 	 count <= MAX_CREDS_ALLOWED && id_cryptoctx->creds[count] != NULL;
53717934SMark.Phalan@Sun.COM 	 count++);
53727934SMark.Phalan@Sun.COM     *cert_count = count;
53737934SMark.Phalan@Sun.COM     return 0;
53747934SMark.Phalan@Sun.COM }
53757934SMark.Phalan@Sun.COM 
53767934SMark.Phalan@Sun.COM 
53777934SMark.Phalan@Sun.COM /*
53787934SMark.Phalan@Sun.COM  * Begin iteration over the certs loaded in crypto_load_certs()
53797934SMark.Phalan@Sun.COM  */
53807934SMark.Phalan@Sun.COM /* ARGSUSED */
53817934SMark.Phalan@Sun.COM krb5_error_code
53827934SMark.Phalan@Sun.COM crypto_cert_iteration_begin(krb5_context context,
53837934SMark.Phalan@Sun.COM 			    pkinit_plg_crypto_context plg_cryptoctx,
53847934SMark.Phalan@Sun.COM 			    pkinit_req_crypto_context req_cryptoctx,
53857934SMark.Phalan@Sun.COM 			    pkinit_identity_crypto_context id_cryptoctx,
53867934SMark.Phalan@Sun.COM 			    pkinit_cert_iter_handle *ih_ret)
53877934SMark.Phalan@Sun.COM {
53887934SMark.Phalan@Sun.COM     struct _pkinit_cert_iter_data *id;
53897934SMark.Phalan@Sun.COM 
53907934SMark.Phalan@Sun.COM     if (id_cryptoctx == NULL || ih_ret == NULL)
53917934SMark.Phalan@Sun.COM 	return EINVAL;
53927934SMark.Phalan@Sun.COM     if (id_cryptoctx->creds[0] == NULL)	/* No cred info available */
53937934SMark.Phalan@Sun.COM 	return ENOENT;
53947934SMark.Phalan@Sun.COM 
53957934SMark.Phalan@Sun.COM     id = calloc(1, sizeof(*id));
53967934SMark.Phalan@Sun.COM     if (id == NULL)
53977934SMark.Phalan@Sun.COM 	return ENOMEM;
53987934SMark.Phalan@Sun.COM     id->magic = ITER_MAGIC;
53997934SMark.Phalan@Sun.COM     id->plgctx = plg_cryptoctx,
54007934SMark.Phalan@Sun.COM     id->reqctx = req_cryptoctx,
54017934SMark.Phalan@Sun.COM     id->idctx = id_cryptoctx;
54027934SMark.Phalan@Sun.COM     id->index = 0;
54037934SMark.Phalan@Sun.COM     *ih_ret = (pkinit_cert_iter_handle) id;
54047934SMark.Phalan@Sun.COM     return 0;
54057934SMark.Phalan@Sun.COM }
54067934SMark.Phalan@Sun.COM 
54077934SMark.Phalan@Sun.COM /*
54087934SMark.Phalan@Sun.COM  * End iteration over the certs loaded in crypto_load_certs()
54097934SMark.Phalan@Sun.COM  */
54107934SMark.Phalan@Sun.COM /* ARGSUSED */
54117934SMark.Phalan@Sun.COM krb5_error_code
54127934SMark.Phalan@Sun.COM crypto_cert_iteration_end(krb5_context context,
54137934SMark.Phalan@Sun.COM 			  pkinit_cert_iter_handle ih)
54147934SMark.Phalan@Sun.COM {
54157934SMark.Phalan@Sun.COM     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
54167934SMark.Phalan@Sun.COM 
54177934SMark.Phalan@Sun.COM     if (id == NULL || id->magic != ITER_MAGIC)
54187934SMark.Phalan@Sun.COM 	return EINVAL;
54197934SMark.Phalan@Sun.COM     free(ih);
54207934SMark.Phalan@Sun.COM     return 0;
54217934SMark.Phalan@Sun.COM }
54227934SMark.Phalan@Sun.COM 
54237934SMark.Phalan@Sun.COM /*
54247934SMark.Phalan@Sun.COM  * Get next certificate handle
54257934SMark.Phalan@Sun.COM  */
54267934SMark.Phalan@Sun.COM /* ARGSUSED */
54277934SMark.Phalan@Sun.COM krb5_error_code
54287934SMark.Phalan@Sun.COM crypto_cert_iteration_next(krb5_context context,
54297934SMark.Phalan@Sun.COM 			   pkinit_cert_iter_handle ih,
54307934SMark.Phalan@Sun.COM 			   pkinit_cert_handle *ch_ret)
54317934SMark.Phalan@Sun.COM {
54327934SMark.Phalan@Sun.COM     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
54337934SMark.Phalan@Sun.COM     struct _pkinit_cert_data *cd;
54347934SMark.Phalan@Sun.COM     pkinit_identity_crypto_context id_cryptoctx;
54357934SMark.Phalan@Sun.COM 
54367934SMark.Phalan@Sun.COM     if (id == NULL || id->magic != ITER_MAGIC)
54377934SMark.Phalan@Sun.COM 	return EINVAL;
54387934SMark.Phalan@Sun.COM 
54397934SMark.Phalan@Sun.COM     if (ch_ret == NULL)
54407934SMark.Phalan@Sun.COM 	return EINVAL;
54417934SMark.Phalan@Sun.COM 
54427934SMark.Phalan@Sun.COM     id_cryptoctx = id->idctx;
54437934SMark.Phalan@Sun.COM     if (id_cryptoctx == NULL)
54447934SMark.Phalan@Sun.COM 	return EINVAL;
54457934SMark.Phalan@Sun.COM 
54467934SMark.Phalan@Sun.COM     if (id_cryptoctx->creds[id->index] == NULL)
54477934SMark.Phalan@Sun.COM 	return PKINIT_ITER_NO_MORE;
54487934SMark.Phalan@Sun.COM 
54497934SMark.Phalan@Sun.COM     cd = calloc(1, sizeof(*cd));
54507934SMark.Phalan@Sun.COM     if (cd == NULL)
54517934SMark.Phalan@Sun.COM 	return ENOMEM;
54527934SMark.Phalan@Sun.COM 
54537934SMark.Phalan@Sun.COM     cd->magic = CERT_MAGIC;
54547934SMark.Phalan@Sun.COM     cd->plgctx = id->plgctx;
54557934SMark.Phalan@Sun.COM     cd->reqctx = id->reqctx;
54567934SMark.Phalan@Sun.COM     cd->idctx = id->idctx;
54577934SMark.Phalan@Sun.COM     cd->index = id->index;
54587934SMark.Phalan@Sun.COM     cd->cred = id_cryptoctx->creds[id->index++];
54597934SMark.Phalan@Sun.COM     *ch_ret = (pkinit_cert_handle)cd;
54607934SMark.Phalan@Sun.COM     return 0;
54617934SMark.Phalan@Sun.COM }
54627934SMark.Phalan@Sun.COM 
54637934SMark.Phalan@Sun.COM /*
54647934SMark.Phalan@Sun.COM  * Release cert handle
54657934SMark.Phalan@Sun.COM  */
54667934SMark.Phalan@Sun.COM /* ARGSUSED */
54677934SMark.Phalan@Sun.COM krb5_error_code
54687934SMark.Phalan@Sun.COM crypto_cert_release(krb5_context context,
54697934SMark.Phalan@Sun.COM 		    pkinit_cert_handle ch)
54707934SMark.Phalan@Sun.COM {
54717934SMark.Phalan@Sun.COM     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
54727934SMark.Phalan@Sun.COM     if (cd == NULL || cd->magic != CERT_MAGIC)
54737934SMark.Phalan@Sun.COM 	return EINVAL;
54747934SMark.Phalan@Sun.COM     free(cd);
54757934SMark.Phalan@Sun.COM     return 0;
54767934SMark.Phalan@Sun.COM }
54777934SMark.Phalan@Sun.COM 
54787934SMark.Phalan@Sun.COM /*
54797934SMark.Phalan@Sun.COM  * Get certificate Key Usage and Extended Key Usage
54807934SMark.Phalan@Sun.COM  */
54817934SMark.Phalan@Sun.COM /* ARGSUSED */
54827934SMark.Phalan@Sun.COM static krb5_error_code
54837934SMark.Phalan@Sun.COM crypto_retieve_X509_key_usage(krb5_context context,
54847934SMark.Phalan@Sun.COM 			      pkinit_plg_crypto_context plgcctx,
54857934SMark.Phalan@Sun.COM 			      pkinit_req_crypto_context reqcctx,
54867934SMark.Phalan@Sun.COM 			      X509 *x,
54877934SMark.Phalan@Sun.COM 			      unsigned int *ret_ku_bits,
54887934SMark.Phalan@Sun.COM 			      unsigned int *ret_eku_bits)
54897934SMark.Phalan@Sun.COM {
54907934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
54917934SMark.Phalan@Sun.COM     int i;
54927934SMark.Phalan@Sun.COM     unsigned int eku_bits = 0, ku_bits = 0;
54937934SMark.Phalan@Sun.COM     ASN1_BIT_STRING *usage = NULL;
54947934SMark.Phalan@Sun.COM 
54957934SMark.Phalan@Sun.COM     if (ret_ku_bits == NULL && ret_eku_bits == NULL)
54967934SMark.Phalan@Sun.COM 	return EINVAL;
54977934SMark.Phalan@Sun.COM 
54987934SMark.Phalan@Sun.COM     if (ret_eku_bits)
54997934SMark.Phalan@Sun.COM 	*ret_eku_bits = 0;
55007934SMark.Phalan@Sun.COM     else {
55017934SMark.Phalan@Sun.COM 	pkiDebug("%s: EKUs not requested, not checking\n", __FUNCTION__);
55027934SMark.Phalan@Sun.COM 	goto check_kus;
55037934SMark.Phalan@Sun.COM     }
55047934SMark.Phalan@Sun.COM 
55057934SMark.Phalan@Sun.COM     /* Start with Extended Key usage */
55067934SMark.Phalan@Sun.COM     i = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
55077934SMark.Phalan@Sun.COM     if (i >= 0) {
55087934SMark.Phalan@Sun.COM 	EXTENDED_KEY_USAGE *eku;
55097934SMark.Phalan@Sun.COM 
55107934SMark.Phalan@Sun.COM 	eku = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL);
55117934SMark.Phalan@Sun.COM 	if (eku) {
55127934SMark.Phalan@Sun.COM 	    for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
55137934SMark.Phalan@Sun.COM 		ASN1_OBJECT *certoid;
55147934SMark.Phalan@Sun.COM 		certoid = sk_ASN1_OBJECT_value(eku, i);
55157934SMark.Phalan@Sun.COM 		if ((OBJ_cmp(certoid, plgcctx->id_pkinit_KPClientAuth)) == 0)
55167934SMark.Phalan@Sun.COM 		    eku_bits |= PKINIT_EKU_PKINIT;
55177934SMark.Phalan@Sun.COM 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_ms_smartcard_login))) == 0)
55187934SMark.Phalan@Sun.COM 		    eku_bits |= PKINIT_EKU_MSSCLOGIN;
55197934SMark.Phalan@Sun.COM 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_client_auth))) == 0)
55207934SMark.Phalan@Sun.COM 		    eku_bits |= PKINIT_EKU_CLIENTAUTH;
55217934SMark.Phalan@Sun.COM 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_email_protect))) == 0)
55227934SMark.Phalan@Sun.COM 		    eku_bits |= PKINIT_EKU_EMAILPROTECTION;
55237934SMark.Phalan@Sun.COM 	    }
55247934SMark.Phalan@Sun.COM 	    EXTENDED_KEY_USAGE_free(eku);
55257934SMark.Phalan@Sun.COM 	}
55267934SMark.Phalan@Sun.COM     }
55277934SMark.Phalan@Sun.COM     pkiDebug("%s: returning eku 0x%08x\n", __FUNCTION__, eku_bits);
55287934SMark.Phalan@Sun.COM     *ret_eku_bits = eku_bits;
55297934SMark.Phalan@Sun.COM 
55307934SMark.Phalan@Sun.COM check_kus:
55317934SMark.Phalan@Sun.COM     /* Now the Key Usage bits */
55327934SMark.Phalan@Sun.COM     if (ret_ku_bits)
55337934SMark.Phalan@Sun.COM 	*ret_ku_bits = 0;
55347934SMark.Phalan@Sun.COM     else {
55357934SMark.Phalan@Sun.COM 	pkiDebug("%s: KUs not requested, not checking\n", __FUNCTION__);
55367934SMark.Phalan@Sun.COM 	goto out;
55377934SMark.Phalan@Sun.COM     }
55387934SMark.Phalan@Sun.COM 
55397934SMark.Phalan@Sun.COM     /* Make sure usage exists before checking bits */
55407934SMark.Phalan@Sun.COM     usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL);
55417934SMark.Phalan@Sun.COM     if (usage) {
55427934SMark.Phalan@Sun.COM 	if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
55437934SMark.Phalan@Sun.COM 	    ku_bits |= PKINIT_KU_DIGITALSIGNATURE;
55447934SMark.Phalan@Sun.COM 	if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
55457934SMark.Phalan@Sun.COM 	    ku_bits |= PKINIT_KU_KEYENCIPHERMENT;
55467934SMark.Phalan@Sun.COM 	ASN1_BIT_STRING_free(usage);
55477934SMark.Phalan@Sun.COM     }
55487934SMark.Phalan@Sun.COM 
55497934SMark.Phalan@Sun.COM     pkiDebug("%s: returning ku 0x%08x\n", __FUNCTION__, ku_bits);
55507934SMark.Phalan@Sun.COM     *ret_ku_bits = ku_bits;
55517934SMark.Phalan@Sun.COM 
55527934SMark.Phalan@Sun.COM out:
55537934SMark.Phalan@Sun.COM     return 0;
55547934SMark.Phalan@Sun.COM }
55557934SMark.Phalan@Sun.COM 
55567934SMark.Phalan@Sun.COM /*
55577934SMark.Phalan@Sun.COM  * Return a string format of an X509_NAME in buf where
55587934SMark.Phalan@Sun.COM  * size is an in/out parameter.  On input it is the size
55597934SMark.Phalan@Sun.COM  * of the buffer, and on output it is the actual length
55607934SMark.Phalan@Sun.COM  * of the name.
55617934SMark.Phalan@Sun.COM  * If buf is NULL, returns the length req'd to hold name
55627934SMark.Phalan@Sun.COM  */
55637934SMark.Phalan@Sun.COM static char *
55647934SMark.Phalan@Sun.COM X509_NAME_oneline_ex(X509_NAME * a,
55657934SMark.Phalan@Sun.COM 		     char *buf,
55667934SMark.Phalan@Sun.COM 		     unsigned int *size,
55677934SMark.Phalan@Sun.COM 		     unsigned long flag)
55687934SMark.Phalan@Sun.COM {
55697934SMark.Phalan@Sun.COM   BIO *out = NULL;
55707934SMark.Phalan@Sun.COM 
55717934SMark.Phalan@Sun.COM   out = BIO_new(BIO_s_mem ());
55727934SMark.Phalan@Sun.COM   if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
55737934SMark.Phalan@Sun.COM     if (buf != NULL && *size > (int) BIO_number_written(out)) {
55747934SMark.Phalan@Sun.COM       (void) memset(buf, 0, *size);
55757934SMark.Phalan@Sun.COM       BIO_read(out, buf, (int) BIO_number_written(out));
55767934SMark.Phalan@Sun.COM     }
55777934SMark.Phalan@Sun.COM     else {
55787934SMark.Phalan@Sun.COM       *size = BIO_number_written(out);
55797934SMark.Phalan@Sun.COM     }
55807934SMark.Phalan@Sun.COM   }
55817934SMark.Phalan@Sun.COM   BIO_free(out);
55827934SMark.Phalan@Sun.COM   return (buf);
55837934SMark.Phalan@Sun.COM }
55847934SMark.Phalan@Sun.COM 
55857934SMark.Phalan@Sun.COM /*
55867934SMark.Phalan@Sun.COM  * Get certificate information
55877934SMark.Phalan@Sun.COM  */
55887934SMark.Phalan@Sun.COM krb5_error_code
55897934SMark.Phalan@Sun.COM crypto_cert_get_matching_data(krb5_context context,
55907934SMark.Phalan@Sun.COM 			      pkinit_cert_handle ch,
55917934SMark.Phalan@Sun.COM 			      pkinit_cert_matching_data **ret_md)
55927934SMark.Phalan@Sun.COM {
55937934SMark.Phalan@Sun.COM     krb5_error_code retval;
55947934SMark.Phalan@Sun.COM     pkinit_cert_matching_data *md;
55957934SMark.Phalan@Sun.COM     krb5_principal *pkinit_sans =NULL, *upn_sans = NULL;
55967934SMark.Phalan@Sun.COM     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
55977934SMark.Phalan@Sun.COM     int i, j;
55987934SMark.Phalan@Sun.COM     char buf[DN_BUF_LEN];
55997934SMark.Phalan@Sun.COM     unsigned int bufsize = sizeof(buf);
56007934SMark.Phalan@Sun.COM 
56017934SMark.Phalan@Sun.COM     if (cd == NULL || cd->magic != CERT_MAGIC)
56027934SMark.Phalan@Sun.COM 	return EINVAL;
56037934SMark.Phalan@Sun.COM     if (ret_md == NULL)
56047934SMark.Phalan@Sun.COM 	return EINVAL;
56057934SMark.Phalan@Sun.COM 
56067934SMark.Phalan@Sun.COM     md = calloc(1, sizeof(*md));
56077934SMark.Phalan@Sun.COM     if (md == NULL)
56087934SMark.Phalan@Sun.COM 	return ENOMEM;
56097934SMark.Phalan@Sun.COM 
56107934SMark.Phalan@Sun.COM     md->ch = ch;
56117934SMark.Phalan@Sun.COM 
56127934SMark.Phalan@Sun.COM     /* get the subject name (in rfc2253 format) */
56137934SMark.Phalan@Sun.COM     X509_NAME_oneline_ex(X509_get_subject_name(cd->cred->cert),
56147934SMark.Phalan@Sun.COM 			 buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
56157934SMark.Phalan@Sun.COM     md->subject_dn = strdup(buf);
56167934SMark.Phalan@Sun.COM     if (md->subject_dn == NULL) {
56177934SMark.Phalan@Sun.COM 	retval = ENOMEM;
56187934SMark.Phalan@Sun.COM 	goto cleanup;
56197934SMark.Phalan@Sun.COM     }
56207934SMark.Phalan@Sun.COM 
56217934SMark.Phalan@Sun.COM     /* get the issuer name (in rfc2253 format) */
56227934SMark.Phalan@Sun.COM     X509_NAME_oneline_ex(X509_get_issuer_name(cd->cred->cert),
56237934SMark.Phalan@Sun.COM 			 buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
56247934SMark.Phalan@Sun.COM     md->issuer_dn = strdup(buf);
56257934SMark.Phalan@Sun.COM     if (md->issuer_dn == NULL) {
56267934SMark.Phalan@Sun.COM 	retval = ENOMEM;
56277934SMark.Phalan@Sun.COM 	goto cleanup;
56287934SMark.Phalan@Sun.COM     }
56297934SMark.Phalan@Sun.COM 
56307934SMark.Phalan@Sun.COM     /* get the san data */
56317934SMark.Phalan@Sun.COM     retval = crypto_retrieve_X509_sans(context, cd->plgctx, cd->reqctx,
56327934SMark.Phalan@Sun.COM 				       cd->cred->cert, &pkinit_sans,
56337934SMark.Phalan@Sun.COM 				       &upn_sans, NULL);
56347934SMark.Phalan@Sun.COM     if (retval)
56357934SMark.Phalan@Sun.COM 	goto cleanup;
56367934SMark.Phalan@Sun.COM 
56377934SMark.Phalan@Sun.COM     j = 0;
56387934SMark.Phalan@Sun.COM     if (pkinit_sans != NULL) {
56397934SMark.Phalan@Sun.COM 	for (i = 0; pkinit_sans[i] != NULL; i++)
56407934SMark.Phalan@Sun.COM 	    j++;
56417934SMark.Phalan@Sun.COM     }
56427934SMark.Phalan@Sun.COM     if (upn_sans != NULL) {
56437934SMark.Phalan@Sun.COM 	for (i = 0; upn_sans[i] != NULL; i++)
56447934SMark.Phalan@Sun.COM 	    j++;
56457934SMark.Phalan@Sun.COM     }
56467934SMark.Phalan@Sun.COM     if (j != 0) {
56477934SMark.Phalan@Sun.COM 	md->sans = calloc((size_t)j+1, sizeof(*md->sans));
56487934SMark.Phalan@Sun.COM 	if (md->sans == NULL) {
56497934SMark.Phalan@Sun.COM 	    retval = ENOMEM;
56507934SMark.Phalan@Sun.COM 	    goto cleanup;
56517934SMark.Phalan@Sun.COM 	}
56527934SMark.Phalan@Sun.COM 	j = 0;
56537934SMark.Phalan@Sun.COM 	if (pkinit_sans != NULL) {
56547934SMark.Phalan@Sun.COM 	    for (i = 0; pkinit_sans[i] != NULL; i++)
56557934SMark.Phalan@Sun.COM 		md->sans[j++] = pkinit_sans[i];
56567934SMark.Phalan@Sun.COM 	    free(pkinit_sans);
56577934SMark.Phalan@Sun.COM 	}
56587934SMark.Phalan@Sun.COM 	if (upn_sans != NULL) {
56597934SMark.Phalan@Sun.COM 	    for (i = 0; upn_sans[i] != NULL; i++)
56607934SMark.Phalan@Sun.COM 		md->sans[j++] = upn_sans[i];
56617934SMark.Phalan@Sun.COM 	    free(upn_sans);
56627934SMark.Phalan@Sun.COM 	}
56637934SMark.Phalan@Sun.COM 	md->sans[j] = NULL;
56647934SMark.Phalan@Sun.COM     } else
56657934SMark.Phalan@Sun.COM 	md->sans = NULL;
56667934SMark.Phalan@Sun.COM 
56677934SMark.Phalan@Sun.COM     /* get the KU and EKU data */
56687934SMark.Phalan@Sun.COM 
56697934SMark.Phalan@Sun.COM     retval = crypto_retieve_X509_key_usage(context, cd->plgctx, cd->reqctx,
56707934SMark.Phalan@Sun.COM 					   cd->cred->cert,
56717934SMark.Phalan@Sun.COM 					   &md->ku_bits, &md->eku_bits);
56727934SMark.Phalan@Sun.COM     if (retval)
56737934SMark.Phalan@Sun.COM 	goto cleanup;
56747934SMark.Phalan@Sun.COM 
56757934SMark.Phalan@Sun.COM     *ret_md = md;
56767934SMark.Phalan@Sun.COM     retval = 0;
56777934SMark.Phalan@Sun.COM cleanup:
56787934SMark.Phalan@Sun.COM     if (retval) {
56797934SMark.Phalan@Sun.COM 	if (md)
56807934SMark.Phalan@Sun.COM 	    crypto_cert_free_matching_data(context, md);
56817934SMark.Phalan@Sun.COM     }
56827934SMark.Phalan@Sun.COM     return retval;
56837934SMark.Phalan@Sun.COM }
56847934SMark.Phalan@Sun.COM 
56857934SMark.Phalan@Sun.COM /*
56867934SMark.Phalan@Sun.COM  * Free certificate information
56877934SMark.Phalan@Sun.COM  */
56887934SMark.Phalan@Sun.COM krb5_error_code
56897934SMark.Phalan@Sun.COM crypto_cert_free_matching_data(krb5_context context,
56907934SMark.Phalan@Sun.COM 		      pkinit_cert_matching_data *md)
56917934SMark.Phalan@Sun.COM {
56927934SMark.Phalan@Sun.COM     krb5_principal p;
56937934SMark.Phalan@Sun.COM     int i;
56947934SMark.Phalan@Sun.COM 
56957934SMark.Phalan@Sun.COM     if (md == NULL)
56967934SMark.Phalan@Sun.COM 	return EINVAL;
56977934SMark.Phalan@Sun.COM     if (md->subject_dn)
56987934SMark.Phalan@Sun.COM 	free(md->subject_dn);
56997934SMark.Phalan@Sun.COM     if (md->issuer_dn)
57007934SMark.Phalan@Sun.COM 	free(md->issuer_dn);
57017934SMark.Phalan@Sun.COM     if (md->sans) {
57027934SMark.Phalan@Sun.COM 	for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i])
57037934SMark.Phalan@Sun.COM 	    krb5_free_principal(context, p);
57047934SMark.Phalan@Sun.COM 	free(md->sans);
57057934SMark.Phalan@Sun.COM     }
57067934SMark.Phalan@Sun.COM     free(md);
57077934SMark.Phalan@Sun.COM     return 0;
57087934SMark.Phalan@Sun.COM }
57097934SMark.Phalan@Sun.COM 
57107934SMark.Phalan@Sun.COM /*
57117934SMark.Phalan@Sun.COM  * Make this matching certificate "the chosen one"
57127934SMark.Phalan@Sun.COM  */
57137934SMark.Phalan@Sun.COM /* ARGSUSED */
57147934SMark.Phalan@Sun.COM krb5_error_code
57157934SMark.Phalan@Sun.COM crypto_cert_select(krb5_context context,
57167934SMark.Phalan@Sun.COM 		   pkinit_cert_matching_data *md)
57177934SMark.Phalan@Sun.COM {
57187934SMark.Phalan@Sun.COM     struct _pkinit_cert_data *cd;
57197934SMark.Phalan@Sun.COM     if (md == NULL)
57207934SMark.Phalan@Sun.COM 	return EINVAL;
57217934SMark.Phalan@Sun.COM 
57227934SMark.Phalan@Sun.COM     cd = (struct _pkinit_cert_data *)md->ch;
57237934SMark.Phalan@Sun.COM     if (cd == NULL || cd->magic != CERT_MAGIC)
57247934SMark.Phalan@Sun.COM 	return EINVAL;
57257934SMark.Phalan@Sun.COM 
57267934SMark.Phalan@Sun.COM     /* copy the selected cert into our id_cryptoctx */
57277934SMark.Phalan@Sun.COM     if (cd->idctx->my_certs != NULL) {
57287934SMark.Phalan@Sun.COM 	sk_X509_pop_free(cd->idctx->my_certs, X509_free);
57297934SMark.Phalan@Sun.COM     }
57307934SMark.Phalan@Sun.COM     cd->idctx->my_certs = sk_X509_new_null();
57317934SMark.Phalan@Sun.COM     sk_X509_push(cd->idctx->my_certs, cd->cred->cert);
57327934SMark.Phalan@Sun.COM     cd->idctx->creds[cd->index]->cert = NULL;	    /* Don't free it twice */
57337934SMark.Phalan@Sun.COM     cd->idctx->cert_index = 0;
57347934SMark.Phalan@Sun.COM 
57357934SMark.Phalan@Sun.COM     if (cd->idctx->pkcs11_method != 1) {
57367934SMark.Phalan@Sun.COM 	cd->idctx->my_key = cd->cred->key;
57377934SMark.Phalan@Sun.COM 	cd->idctx->creds[cd->index]->key = NULL;    /* Don't free it twice */
57387934SMark.Phalan@Sun.COM     }
57397934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
57407934SMark.Phalan@Sun.COM     else {
57417934SMark.Phalan@Sun.COM 	cd->idctx->cert_id = cd->cred->cert_id;
57427934SMark.Phalan@Sun.COM 	cd->idctx->creds[cd->index]->cert_id = NULL; /* Don't free it twice */
57437934SMark.Phalan@Sun.COM 	cd->idctx->cert_id_len = cd->cred->cert_id_len;
57447934SMark.Phalan@Sun.COM     }
57457934SMark.Phalan@Sun.COM #endif
57467934SMark.Phalan@Sun.COM     return 0;
57477934SMark.Phalan@Sun.COM }
57487934SMark.Phalan@Sun.COM 
57497934SMark.Phalan@Sun.COM /*
57507934SMark.Phalan@Sun.COM  * Choose the default certificate as "the chosen one"
57517934SMark.Phalan@Sun.COM  */
57527934SMark.Phalan@Sun.COM krb5_error_code
57537934SMark.Phalan@Sun.COM crypto_cert_select_default(krb5_context context,
57547934SMark.Phalan@Sun.COM 			   pkinit_plg_crypto_context plg_cryptoctx,
57557934SMark.Phalan@Sun.COM 			   pkinit_req_crypto_context req_cryptoctx,
57567934SMark.Phalan@Sun.COM 			   pkinit_identity_crypto_context id_cryptoctx)
57577934SMark.Phalan@Sun.COM {
57587934SMark.Phalan@Sun.COM     krb5_error_code retval;
57597934SMark.Phalan@Sun.COM     int cert_count = 0;
57607934SMark.Phalan@Sun.COM 
57617934SMark.Phalan@Sun.COM     retval = crypto_cert_get_count(context, plg_cryptoctx, req_cryptoctx,
57627934SMark.Phalan@Sun.COM 				   id_cryptoctx, &cert_count);
57637934SMark.Phalan@Sun.COM     if (retval) {
57647934SMark.Phalan@Sun.COM 	pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
57657934SMark.Phalan@Sun.COM 		 __FUNCTION__, retval, error_message(retval));
57667934SMark.Phalan@Sun.COM 	goto errout;
57677934SMark.Phalan@Sun.COM     }
57687934SMark.Phalan@Sun.COM     if (cert_count != 1) {
57697934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Improved error messages */
57707934SMark.Phalan@Sun.COM 	retval = EINVAL;
57717934SMark.Phalan@Sun.COM 	krb5_set_error_message(context, retval,
5772*12945Swill.fiveash@oracle.com 	    gettext("Failed to select default certificate: "
57737934SMark.Phalan@Sun.COM 	        "found %d certs to choose from but there must be exactly one"),
57747934SMark.Phalan@Sun.COM 	    cert_count);
57757934SMark.Phalan@Sun.COM 	pkiDebug("%s: ERROR: There are %d certs to choose from, "
57767934SMark.Phalan@Sun.COM 		 "but there must be exactly one.\n",
57777934SMark.Phalan@Sun.COM 		 __FUNCTION__, cert_count);
57787934SMark.Phalan@Sun.COM 	goto errout;
57797934SMark.Phalan@Sun.COM     }
57807934SMark.Phalan@Sun.COM     /* copy the selected cert into our id_cryptoctx */
57817934SMark.Phalan@Sun.COM     if (id_cryptoctx->my_certs != NULL) {
57827934SMark.Phalan@Sun.COM 	sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
57837934SMark.Phalan@Sun.COM     }
57847934SMark.Phalan@Sun.COM     id_cryptoctx->my_certs = sk_X509_new_null();
57857934SMark.Phalan@Sun.COM     sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
57867934SMark.Phalan@Sun.COM     id_cryptoctx->creds[0]->cert = NULL;	/* Don't free it twice */
57877934SMark.Phalan@Sun.COM     id_cryptoctx->cert_index = 0;
57887934SMark.Phalan@Sun.COM 
57897934SMark.Phalan@Sun.COM     if (id_cryptoctx->pkcs11_method != 1) {
57907934SMark.Phalan@Sun.COM 	id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
57917934SMark.Phalan@Sun.COM 	id_cryptoctx->creds[0]->key = NULL;	/* Don't free it twice */
57927934SMark.Phalan@Sun.COM     }
57937934SMark.Phalan@Sun.COM #ifndef WITHOUT_PKCS11
57947934SMark.Phalan@Sun.COM     else {
57957934SMark.Phalan@Sun.COM 	id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
57967934SMark.Phalan@Sun.COM 	id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
57977934SMark.Phalan@Sun.COM 	id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
57987934SMark.Phalan@Sun.COM     }
57997934SMark.Phalan@Sun.COM #endif
58007934SMark.Phalan@Sun.COM     retval = 0;
58017934SMark.Phalan@Sun.COM errout:
58027934SMark.Phalan@Sun.COM     return retval;
58037934SMark.Phalan@Sun.COM }
58047934SMark.Phalan@Sun.COM 
58057934SMark.Phalan@Sun.COM 
58067934SMark.Phalan@Sun.COM /* ARGSUSED */
58077934SMark.Phalan@Sun.COM static krb5_error_code
58087934SMark.Phalan@Sun.COM load_cas_and_crls(krb5_context context,
58097934SMark.Phalan@Sun.COM 		  pkinit_plg_crypto_context plg_cryptoctx,
58107934SMark.Phalan@Sun.COM 		  pkinit_req_crypto_context req_cryptoctx,
58117934SMark.Phalan@Sun.COM 		  pkinit_identity_crypto_context id_cryptoctx,
58127934SMark.Phalan@Sun.COM 		  int catype,
58137934SMark.Phalan@Sun.COM 		  char *filename)
58147934SMark.Phalan@Sun.COM {
58157934SMark.Phalan@Sun.COM     STACK_OF(X509_INFO) *sk = NULL;
58167934SMark.Phalan@Sun.COM     STACK_OF(X509) *ca_certs = NULL;
58177934SMark.Phalan@Sun.COM     STACK_OF(X509_CRL) *ca_crls = NULL;
58187934SMark.Phalan@Sun.COM     BIO *in = NULL;
58197934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
58207934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
58217934SMark.Phalan@Sun.COM     int i = 0;
58227934SMark.Phalan@Sun.COM 
58237934SMark.Phalan@Sun.COM     /* If there isn't already a stack in the context,
58247934SMark.Phalan@Sun.COM      * create a temporary one now */
58257934SMark.Phalan@Sun.COM     switch(catype) {
58267934SMark.Phalan@Sun.COM     case CATYPE_ANCHORS:
58277934SMark.Phalan@Sun.COM 	if (id_cryptoctx->trustedCAs != NULL)
58287934SMark.Phalan@Sun.COM 	    ca_certs = id_cryptoctx->trustedCAs;
58297934SMark.Phalan@Sun.COM 	else {
58307934SMark.Phalan@Sun.COM 	    ca_certs = sk_X509_new_null();
58317934SMark.Phalan@Sun.COM 	    if (ca_certs == NULL)
58327934SMark.Phalan@Sun.COM 		return ENOMEM;
58337934SMark.Phalan@Sun.COM 	}
58347934SMark.Phalan@Sun.COM 	break;
58357934SMark.Phalan@Sun.COM     case CATYPE_INTERMEDIATES:
58367934SMark.Phalan@Sun.COM 	if (id_cryptoctx->intermediateCAs != NULL)
58377934SMark.Phalan@Sun.COM 	    ca_certs = id_cryptoctx->intermediateCAs;
58387934SMark.Phalan@Sun.COM 	else {
58397934SMark.Phalan@Sun.COM 	    ca_certs = sk_X509_new_null();
58407934SMark.Phalan@Sun.COM 	    if (ca_certs == NULL)
58417934SMark.Phalan@Sun.COM 		return ENOMEM;
58427934SMark.Phalan@Sun.COM 	}
58437934SMark.Phalan@Sun.COM 	break;
58447934SMark.Phalan@Sun.COM     case CATYPE_CRLS:
58457934SMark.Phalan@Sun.COM 	if (id_cryptoctx->revoked != NULL)
58467934SMark.Phalan@Sun.COM 	    ca_crls = id_cryptoctx->revoked;
58477934SMark.Phalan@Sun.COM 	else {
58487934SMark.Phalan@Sun.COM 	    ca_crls = sk_X509_CRL_new_null();
58497934SMark.Phalan@Sun.COM 	    if (ca_crls == NULL)
58507934SMark.Phalan@Sun.COM 		return ENOMEM;
58517934SMark.Phalan@Sun.COM 	}
58527934SMark.Phalan@Sun.COM 	break;
58537934SMark.Phalan@Sun.COM     default:
58547934SMark.Phalan@Sun.COM 	return ENOTSUP;
58557934SMark.Phalan@Sun.COM     }
58567934SMark.Phalan@Sun.COM 
58577934SMark.Phalan@Sun.COM     if (!(in = BIO_new_file(filename, "r"))) {
58587934SMark.Phalan@Sun.COM 	retval = errno;
58597934SMark.Phalan@Sun.COM 	pkiDebug("%s: error opening file '%s': %s\n", __FUNCTION__,
58607934SMark.Phalan@Sun.COM 		 filename, error_message(errno));
58617934SMark.Phalan@Sun.COM 	goto cleanup;
58627934SMark.Phalan@Sun.COM     }
58637934SMark.Phalan@Sun.COM 
58647934SMark.Phalan@Sun.COM     /* This loads from a file, a stack of x509/crl/pkey sets */
58657934SMark.Phalan@Sun.COM     if ((sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) {
58667934SMark.Phalan@Sun.COM 	pkiDebug("%s: error reading file '%s'\n", __FUNCTION__, filename);
58677934SMark.Phalan@Sun.COM 	retval = EIO;
58687934SMark.Phalan@Sun.COM 	goto cleanup;
58697934SMark.Phalan@Sun.COM     }
58707934SMark.Phalan@Sun.COM 
58717934SMark.Phalan@Sun.COM     /* scan over the stack created from loading the file contents,
58727934SMark.Phalan@Sun.COM      * weed out duplicates, and push new ones onto the return stack
58737934SMark.Phalan@Sun.COM      */
58747934SMark.Phalan@Sun.COM     for (i = 0; i < sk_X509_INFO_num(sk); i++) {
58757934SMark.Phalan@Sun.COM 	X509_INFO *xi = sk_X509_INFO_value(sk, i);
58767934SMark.Phalan@Sun.COM 	if (xi != NULL && xi->x509 != NULL && catype != CATYPE_CRLS) {
58777934SMark.Phalan@Sun.COM 	    int j = 0, size = sk_X509_num(ca_certs), flag = 0;
58787934SMark.Phalan@Sun.COM 
58797934SMark.Phalan@Sun.COM 	    if (!size) {
58807934SMark.Phalan@Sun.COM 		sk_X509_push(ca_certs, xi->x509);
58817934SMark.Phalan@Sun.COM 		xi->x509 = NULL;
58827934SMark.Phalan@Sun.COM 		continue;
58837934SMark.Phalan@Sun.COM 	    }
58847934SMark.Phalan@Sun.COM 	    for (j = 0; j < size; j++) {
58857934SMark.Phalan@Sun.COM 		X509 *x = sk_X509_value(ca_certs, j);
58867934SMark.Phalan@Sun.COM 		flag = X509_cmp(x, xi->x509);
58877934SMark.Phalan@Sun.COM 		if (flag == 0)
58887934SMark.Phalan@Sun.COM 		    break;
58897934SMark.Phalan@Sun.COM 		else
58907934SMark.Phalan@Sun.COM 		    continue;
58917934SMark.Phalan@Sun.COM 	    }
58927934SMark.Phalan@Sun.COM 	    if (flag != 0) {
58937934SMark.Phalan@Sun.COM 		sk_X509_push(ca_certs, X509_dup(xi->x509));
58947934SMark.Phalan@Sun.COM 	    }
58957934SMark.Phalan@Sun.COM 	} else if (xi != NULL && xi->crl != NULL && catype == CATYPE_CRLS) {
58967934SMark.Phalan@Sun.COM 	    int j = 0, size = sk_X509_CRL_num(ca_crls), flag = 0;
58977934SMark.Phalan@Sun.COM 	    if (!size) {
58987934SMark.Phalan@Sun.COM 		sk_X509_CRL_push(ca_crls, xi->crl);
58997934SMark.Phalan@Sun.COM 		xi->crl = NULL;
59007934SMark.Phalan@Sun.COM 		continue;
59017934SMark.Phalan@Sun.COM 	    }
59027934SMark.Phalan@Sun.COM 	    for (j = 0; j < size; j++) {
59037934SMark.Phalan@Sun.COM 		X509_CRL *x = sk_X509_CRL_value(ca_crls, j);
59047934SMark.Phalan@Sun.COM 		flag = X509_CRL_cmp(x, xi->crl);
59057934SMark.Phalan@Sun.COM 		if (flag == 0)
59067934SMark.Phalan@Sun.COM 		    break;
59077934SMark.Phalan@Sun.COM 		else
59087934SMark.Phalan@Sun.COM 		    continue;
59097934SMark.Phalan@Sun.COM 	    }
59107934SMark.Phalan@Sun.COM 	    if (flag != 0) {
59117934SMark.Phalan@Sun.COM 		sk_X509_push(ca_crls, X509_CRL_dup(xi->crl));
59127934SMark.Phalan@Sun.COM 	    }
59137934SMark.Phalan@Sun.COM 	}
59147934SMark.Phalan@Sun.COM     }
59157934SMark.Phalan@Sun.COM 
59167934SMark.Phalan@Sun.COM     /* If we added something and there wasn't a stack in the
59177934SMark.Phalan@Sun.COM      * context before, add the temporary stack to the context.
59187934SMark.Phalan@Sun.COM      */
59197934SMark.Phalan@Sun.COM     switch(catype) {
59207934SMark.Phalan@Sun.COM     case CATYPE_ANCHORS:
59217934SMark.Phalan@Sun.COM 	if (sk_X509_num(ca_certs) == 0) {
59227934SMark.Phalan@Sun.COM 	    pkiDebug("no anchors in file, %s\n", filename);
59237934SMark.Phalan@Sun.COM 	    if (id_cryptoctx->trustedCAs == NULL)
59247934SMark.Phalan@Sun.COM 		sk_X509_free(ca_certs);
59257934SMark.Phalan@Sun.COM 	} else {
59267934SMark.Phalan@Sun.COM 	    if (id_cryptoctx->trustedCAs == NULL)
59277934SMark.Phalan@Sun.COM 		id_cryptoctx->trustedCAs = ca_certs;
59287934SMark.Phalan@Sun.COM 	}
59297934SMark.Phalan@Sun.COM 	break;
59307934SMark.Phalan@Sun.COM     case CATYPE_INTERMEDIATES:
59317934SMark.Phalan@Sun.COM 	if (sk_X509_num(ca_certs) == 0) {
59327934SMark.Phalan@Sun.COM 	    pkiDebug("no intermediates in file, %s\n", filename);
59337934SMark.Phalan@Sun.COM 	    if (id_cryptoctx->intermediateCAs == NULL)
59347934SMark.Phalan@Sun.COM 		sk_X509_free(ca_certs);
59357934SMark.Phalan@Sun.COM 	} else {
59367934SMark.Phalan@Sun.COM 	    if (id_cryptoctx->intermediateCAs == NULL)
59377934SMark.Phalan@Sun.COM 		id_cryptoctx->intermediateCAs = ca_certs;
59387934SMark.Phalan@Sun.COM 	}
59397934SMark.Phalan@Sun.COM 	break;
59407934SMark.Phalan@Sun.COM     case CATYPE_CRLS:
59417934SMark.Phalan@Sun.COM 	if (sk_X509_num(ca_crls) == 0) {
59427934SMark.Phalan@Sun.COM 	    pkiDebug("no crls in file, %s\n", filename);
59437934SMark.Phalan@Sun.COM 	    if (id_cryptoctx->revoked == NULL)
59447934SMark.Phalan@Sun.COM 		sk_X509_CRL_free(ca_crls);
59457934SMark.Phalan@Sun.COM 	} else {
59467934SMark.Phalan@Sun.COM 	    if (id_cryptoctx->revoked == NULL)
59477934SMark.Phalan@Sun.COM 		id_cryptoctx->revoked = ca_crls;
59487934SMark.Phalan@Sun.COM 	}
59497934SMark.Phalan@Sun.COM 	break;
59507934SMark.Phalan@Sun.COM     default:
59517934SMark.Phalan@Sun.COM 	/* Should have been caught above! */
59527934SMark.Phalan@Sun.COM 	retval = EINVAL;
59537934SMark.Phalan@Sun.COM 	goto cleanup;
59547934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: removed "break" as it's never reached */
59557934SMark.Phalan@Sun.COM     }
59567934SMark.Phalan@Sun.COM 
59577934SMark.Phalan@Sun.COM     retval = 0;
59587934SMark.Phalan@Sun.COM 
59597934SMark.Phalan@Sun.COM   cleanup:
59607934SMark.Phalan@Sun.COM     if (in != NULL)
59617934SMark.Phalan@Sun.COM 	BIO_free(in);
59627934SMark.Phalan@Sun.COM     if (sk != NULL)
59637934SMark.Phalan@Sun.COM 	sk_X509_INFO_pop_free(sk, X509_INFO_free);
59647934SMark.Phalan@Sun.COM 
59657934SMark.Phalan@Sun.COM     return retval;
59667934SMark.Phalan@Sun.COM }
59677934SMark.Phalan@Sun.COM 
59687934SMark.Phalan@Sun.COM static krb5_error_code
59697934SMark.Phalan@Sun.COM load_cas_and_crls_dir(krb5_context context,
59707934SMark.Phalan@Sun.COM 		      pkinit_plg_crypto_context plg_cryptoctx,
59717934SMark.Phalan@Sun.COM 		      pkinit_req_crypto_context req_cryptoctx,
59727934SMark.Phalan@Sun.COM 		      pkinit_identity_crypto_context id_cryptoctx,
59737934SMark.Phalan@Sun.COM 		      int catype,
59747934SMark.Phalan@Sun.COM 		      char *dirname)
59757934SMark.Phalan@Sun.COM {
59767934SMark.Phalan@Sun.COM     krb5_error_code retval = EINVAL;
59777934SMark.Phalan@Sun.COM     DIR *d = NULL;
59787934SMark.Phalan@Sun.COM     struct dirent *dentry = NULL;
59797934SMark.Phalan@Sun.COM     char filename[1024];
59807934SMark.Phalan@Sun.COM 
59817934SMark.Phalan@Sun.COM     if (dirname == NULL)
59827934SMark.Phalan@Sun.COM 	return EINVAL;
59837934SMark.Phalan@Sun.COM 
59847934SMark.Phalan@Sun.COM     d = opendir(dirname);
59857934SMark.Phalan@Sun.COM     if (d == NULL)
59867934SMark.Phalan@Sun.COM 	return ENOENT;
59877934SMark.Phalan@Sun.COM 
59887934SMark.Phalan@Sun.COM     while ((dentry = readdir(d))) {
59897934SMark.Phalan@Sun.COM 	if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(filename)) {
59907934SMark.Phalan@Sun.COM 	    pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
59917934SMark.Phalan@Sun.COM 		     __FUNCTION__, dirname, dentry->d_name);
59927934SMark.Phalan@Sun.COM 	    goto cleanup;
59937934SMark.Phalan@Sun.COM 	}
59947934SMark.Phalan@Sun.COM 	/* Ignore subdirectories and anything starting with a dot */
59957934SMark.Phalan@Sun.COM #ifdef DT_DIR
59967934SMark.Phalan@Sun.COM 	if (dentry->d_type == DT_DIR)
59977934SMark.Phalan@Sun.COM 	    continue;
59987934SMark.Phalan@Sun.COM #endif
59997934SMark.Phalan@Sun.COM 	if (dentry->d_name[0] == '.')
60007934SMark.Phalan@Sun.COM 	    continue;
60017934SMark.Phalan@Sun.COM 	(void) snprintf(filename, sizeof(filename), "%s/%s", dirname, dentry->d_name);
60027934SMark.Phalan@Sun.COM 
60037934SMark.Phalan@Sun.COM 	retval = load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
60047934SMark.Phalan@Sun.COM 				   id_cryptoctx, catype, filename);
60057934SMark.Phalan@Sun.COM 	if (retval)
60067934SMark.Phalan@Sun.COM 	    goto cleanup;
60077934SMark.Phalan@Sun.COM     }
60087934SMark.Phalan@Sun.COM 
60097934SMark.Phalan@Sun.COM     retval = 0;
60107934SMark.Phalan@Sun.COM 
60117934SMark.Phalan@Sun.COM   cleanup:
60127934SMark.Phalan@Sun.COM     if (d != NULL)
60137934SMark.Phalan@Sun.COM 	(void) closedir(d);
60147934SMark.Phalan@Sun.COM 
60157934SMark.Phalan@Sun.COM     return retval;
60167934SMark.Phalan@Sun.COM }
60177934SMark.Phalan@Sun.COM 
60187934SMark.Phalan@Sun.COM /* ARGSUSED */
60197934SMark.Phalan@Sun.COM krb5_error_code
60207934SMark.Phalan@Sun.COM crypto_load_cas_and_crls(krb5_context context,
60217934SMark.Phalan@Sun.COM 			 pkinit_plg_crypto_context plg_cryptoctx,
60227934SMark.Phalan@Sun.COM 			 pkinit_req_crypto_context req_cryptoctx,
60237934SMark.Phalan@Sun.COM 			 pkinit_identity_opts *idopts,
60247934SMark.Phalan@Sun.COM 			 pkinit_identity_crypto_context id_cryptoctx,
60257934SMark.Phalan@Sun.COM 			 int idtype,
60267934SMark.Phalan@Sun.COM 			 int catype,
60277934SMark.Phalan@Sun.COM 			 char *id)
60287934SMark.Phalan@Sun.COM {
60297934SMark.Phalan@Sun.COM     pkiDebug("%s: called with idtype %s and catype %s\n",
60307934SMark.Phalan@Sun.COM 	     __FUNCTION__, idtype2string(idtype), catype2string(catype));
60317934SMark.Phalan@Sun.COM     /* Solaris Kerberos: Removed "break"'s as they are never reached */
60327934SMark.Phalan@Sun.COM     switch (idtype) {
60337934SMark.Phalan@Sun.COM     case IDTYPE_FILE:
60347934SMark.Phalan@Sun.COM 	return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
60357934SMark.Phalan@Sun.COM 				 id_cryptoctx, catype, id);
60367934SMark.Phalan@Sun.COM     case IDTYPE_DIR:
60377934SMark.Phalan@Sun.COM 	return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
60387934SMark.Phalan@Sun.COM 				     id_cryptoctx, catype, id);
60397934SMark.Phalan@Sun.COM     default:
60407934SMark.Phalan@Sun.COM 	return ENOTSUP;
60417934SMark.Phalan@Sun.COM     }
60427934SMark.Phalan@Sun.COM }
60437934SMark.Phalan@Sun.COM 
60447934SMark.Phalan@Sun.COM static krb5_error_code
60457934SMark.Phalan@Sun.COM create_identifiers_from_stack(STACK_OF(X509) *sk,
60467934SMark.Phalan@Sun.COM 			      krb5_external_principal_identifier *** ids)
60477934SMark.Phalan@Sun.COM {
60487934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
60497934SMark.Phalan@Sun.COM     int i = 0, sk_size = sk_X509_num(sk);
60507934SMark.Phalan@Sun.COM     krb5_external_principal_identifier **krb5_cas = NULL;
60517934SMark.Phalan@Sun.COM     X509 *x = NULL;
60527934SMark.Phalan@Sun.COM     X509_NAME *xn = NULL;
60537934SMark.Phalan@Sun.COM     unsigned char *p = NULL;
60547934SMark.Phalan@Sun.COM     int len = 0;
60557934SMark.Phalan@Sun.COM     PKCS7_ISSUER_AND_SERIAL *is = NULL;
60567934SMark.Phalan@Sun.COM     char buf[DN_BUF_LEN];
60577934SMark.Phalan@Sun.COM 
60587934SMark.Phalan@Sun.COM     *ids = NULL;
60597934SMark.Phalan@Sun.COM 
60607934SMark.Phalan@Sun.COM     krb5_cas =
60617934SMark.Phalan@Sun.COM 	malloc((sk_size + 1) * sizeof(krb5_external_principal_identifier *));
60627934SMark.Phalan@Sun.COM     if (krb5_cas == NULL)
60637934SMark.Phalan@Sun.COM 	return ENOMEM;
60647934SMark.Phalan@Sun.COM     krb5_cas[sk_size] = NULL;
60657934SMark.Phalan@Sun.COM 
60667934SMark.Phalan@Sun.COM     for (i = 0; i < sk_size; i++) {
60677934SMark.Phalan@Sun.COM 	krb5_cas[i] = (krb5_external_principal_identifier *)malloc(sizeof(krb5_external_principal_identifier));
60687934SMark.Phalan@Sun.COM 
60697934SMark.Phalan@Sun.COM 	x = sk_X509_value(sk, i);
60707934SMark.Phalan@Sun.COM 
60717934SMark.Phalan@Sun.COM 	X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
60727934SMark.Phalan@Sun.COM 	pkiDebug("#%d cert= %s\n", i, buf);
60737934SMark.Phalan@Sun.COM 
60747934SMark.Phalan@Sun.COM 	/* fill-in subjectName */
60757934SMark.Phalan@Sun.COM 	krb5_cas[i]->subjectName.magic = 0;
60767934SMark.Phalan@Sun.COM 	krb5_cas[i]->subjectName.length = 0;
60777934SMark.Phalan@Sun.COM 	krb5_cas[i]->subjectName.data = NULL;
60787934SMark.Phalan@Sun.COM 
60797934SMark.Phalan@Sun.COM 	xn = X509_get_subject_name(x);
60807934SMark.Phalan@Sun.COM 	len = i2d_X509_NAME(xn, NULL);
60817934SMark.Phalan@Sun.COM 	if ((p = krb5_cas[i]->subjectName.data = (unsigned char *)malloc((size_t) len)) == NULL)
60827934SMark.Phalan@Sun.COM 	    goto cleanup;
60837934SMark.Phalan@Sun.COM 	i2d_X509_NAME(xn, &p);
60847934SMark.Phalan@Sun.COM 	krb5_cas[i]->subjectName.length = len;
60857934SMark.Phalan@Sun.COM 
60867934SMark.Phalan@Sun.COM 	/* fill-in issuerAndSerialNumber */
60877934SMark.Phalan@Sun.COM 	krb5_cas[i]->issuerAndSerialNumber.length = 0;
60887934SMark.Phalan@Sun.COM 	krb5_cas[i]->issuerAndSerialNumber.magic = 0;
60897934SMark.Phalan@Sun.COM 	krb5_cas[i]->issuerAndSerialNumber.data = NULL;
60907934SMark.Phalan@Sun.COM 
60917934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
60927934SMark.Phalan@Sun.COM if (longhorn == 0) { /* XXX Longhorn doesn't like this */
60937934SMark.Phalan@Sun.COM #endif
60947934SMark.Phalan@Sun.COM 	is = PKCS7_ISSUER_AND_SERIAL_new();
60957934SMark.Phalan@Sun.COM 	X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
60967934SMark.Phalan@Sun.COM 	M_ASN1_INTEGER_free(is->serial);
60977934SMark.Phalan@Sun.COM 	is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
60987934SMark.Phalan@Sun.COM 	len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
60997934SMark.Phalan@Sun.COM 	if ((p = krb5_cas[i]->issuerAndSerialNumber.data =
61007934SMark.Phalan@Sun.COM 	     (unsigned char *)malloc((size_t) len)) == NULL)
61017934SMark.Phalan@Sun.COM 	    goto cleanup;
61027934SMark.Phalan@Sun.COM 	i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
61037934SMark.Phalan@Sun.COM 	krb5_cas[i]->issuerAndSerialNumber.length = len;
61047934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
61057934SMark.Phalan@Sun.COM }
61067934SMark.Phalan@Sun.COM #endif
61077934SMark.Phalan@Sun.COM 
61087934SMark.Phalan@Sun.COM 	/* fill-in subjectKeyIdentifier */
61097934SMark.Phalan@Sun.COM 	krb5_cas[i]->subjectKeyIdentifier.length = 0;
61107934SMark.Phalan@Sun.COM 	krb5_cas[i]->subjectKeyIdentifier.magic = 0;
61117934SMark.Phalan@Sun.COM 	krb5_cas[i]->subjectKeyIdentifier.data = NULL;
61127934SMark.Phalan@Sun.COM 
61137934SMark.Phalan@Sun.COM 
61147934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
61157934SMark.Phalan@Sun.COM if (longhorn == 0) {	/* XXX Longhorn doesn't like this */
61167934SMark.Phalan@Sun.COM #endif
61177934SMark.Phalan@Sun.COM 	if (X509_get_ext_by_NID(x, NID_subject_key_identifier, -1) >= 0) {
61187934SMark.Phalan@Sun.COM 	    ASN1_OCTET_STRING *ikeyid = NULL;
61197934SMark.Phalan@Sun.COM 
61207934SMark.Phalan@Sun.COM 	    if ((ikeyid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL,
61217934SMark.Phalan@Sun.COM 					   NULL))) {
61227934SMark.Phalan@Sun.COM 		len = i2d_ASN1_OCTET_STRING(ikeyid, NULL);
61237934SMark.Phalan@Sun.COM 		if ((p = krb5_cas[i]->subjectKeyIdentifier.data =
61247934SMark.Phalan@Sun.COM 			(unsigned char *)malloc((size_t) len)) == NULL)
61257934SMark.Phalan@Sun.COM 		    goto cleanup;
61267934SMark.Phalan@Sun.COM 		i2d_ASN1_OCTET_STRING(ikeyid, &p);
61277934SMark.Phalan@Sun.COM 		krb5_cas[i]->subjectKeyIdentifier.length = len;
61287934SMark.Phalan@Sun.COM 	    }
61297934SMark.Phalan@Sun.COM 	    if (ikeyid != NULL)
61307934SMark.Phalan@Sun.COM 		ASN1_OCTET_STRING_free(ikeyid);
61317934SMark.Phalan@Sun.COM 	}
61327934SMark.Phalan@Sun.COM #ifdef LONGHORN_BETA_COMPAT
61337934SMark.Phalan@Sun.COM }
61347934SMark.Phalan@Sun.COM #endif
61357934SMark.Phalan@Sun.COM 	if (is != NULL) {
61367934SMark.Phalan@Sun.COM 	    if (is->issuer != NULL)
61377934SMark.Phalan@Sun.COM 		X509_NAME_free(is->issuer);
61387934SMark.Phalan@Sun.COM 	    if (is->serial != NULL)
61397934SMark.Phalan@Sun.COM 		ASN1_INTEGER_free(is->serial);
61407934SMark.Phalan@Sun.COM 	    free(is);
61417934SMark.Phalan@Sun.COM 	}
61427934SMark.Phalan@Sun.COM     }
61437934SMark.Phalan@Sun.COM 
61447934SMark.Phalan@Sun.COM     *ids = krb5_cas;
61457934SMark.Phalan@Sun.COM 
61467934SMark.Phalan@Sun.COM     retval = 0;
61477934SMark.Phalan@Sun.COM   cleanup:
61487934SMark.Phalan@Sun.COM     if (retval)
61497934SMark.Phalan@Sun.COM 	free_krb5_external_principal_identifier(&krb5_cas);
61507934SMark.Phalan@Sun.COM 
61517934SMark.Phalan@Sun.COM     return retval;
61527934SMark.Phalan@Sun.COM }
61537934SMark.Phalan@Sun.COM 
61547934SMark.Phalan@Sun.COM /* ARGSUSED */
61557934SMark.Phalan@Sun.COM static krb5_error_code
61567934SMark.Phalan@Sun.COM create_krb5_invalidCertificates(krb5_context context,
61577934SMark.Phalan@Sun.COM 				pkinit_plg_crypto_context plg_cryptoctx,
61587934SMark.Phalan@Sun.COM 				pkinit_req_crypto_context req_cryptoctx,
61597934SMark.Phalan@Sun.COM 				pkinit_identity_crypto_context id_cryptoctx,
61607934SMark.Phalan@Sun.COM 				krb5_external_principal_identifier *** ids)
61617934SMark.Phalan@Sun.COM {
61627934SMark.Phalan@Sun.COM 
61637934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
61647934SMark.Phalan@Sun.COM     STACK_OF(X509) *sk = NULL;
61657934SMark.Phalan@Sun.COM 
61667934SMark.Phalan@Sun.COM     *ids = NULL;
61677934SMark.Phalan@Sun.COM     if (req_cryptoctx->received_cert == NULL)
61687934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
61697934SMark.Phalan@Sun.COM 
61707934SMark.Phalan@Sun.COM     sk = sk_X509_new_null();
61717934SMark.Phalan@Sun.COM     if (sk == NULL)
61727934SMark.Phalan@Sun.COM 	goto cleanup;
61737934SMark.Phalan@Sun.COM     sk_X509_push(sk, req_cryptoctx->received_cert);
61747934SMark.Phalan@Sun.COM 
61757934SMark.Phalan@Sun.COM     retval = create_identifiers_from_stack(sk, ids);
61767934SMark.Phalan@Sun.COM 
61777934SMark.Phalan@Sun.COM     sk_X509_free(sk);
61787934SMark.Phalan@Sun.COM cleanup:
61797934SMark.Phalan@Sun.COM 
61807934SMark.Phalan@Sun.COM     return retval;
61817934SMark.Phalan@Sun.COM }
61827934SMark.Phalan@Sun.COM 
61837934SMark.Phalan@Sun.COM /* ARGSUSED */
61847934SMark.Phalan@Sun.COM krb5_error_code
61857934SMark.Phalan@Sun.COM create_krb5_supportedCMSTypes(krb5_context context,
61867934SMark.Phalan@Sun.COM 			      pkinit_plg_crypto_context plg_cryptoctx,
61877934SMark.Phalan@Sun.COM 			      pkinit_req_crypto_context req_cryptoctx,
61887934SMark.Phalan@Sun.COM 			      pkinit_identity_crypto_context id_cryptoctx,
61897934SMark.Phalan@Sun.COM 			      krb5_algorithm_identifier ***oids)
61907934SMark.Phalan@Sun.COM {
61917934SMark.Phalan@Sun.COM 
61927934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
61937934SMark.Phalan@Sun.COM     krb5_algorithm_identifier **loids = NULL;
61947934SMark.Phalan@Sun.COM     krb5_octet_data des3oid = {0, 8, (unsigned char *)"\x2A\x86\x48\x86\xF7\x0D\x03\x07" };
61957934SMark.Phalan@Sun.COM 
61967934SMark.Phalan@Sun.COM     *oids = NULL;
61977934SMark.Phalan@Sun.COM     loids = malloc(2 * sizeof(krb5_algorithm_identifier *));
61987934SMark.Phalan@Sun.COM     if (loids == NULL)
61997934SMark.Phalan@Sun.COM 	goto cleanup;
62007934SMark.Phalan@Sun.COM     loids[1] = NULL;
62017934SMark.Phalan@Sun.COM     loids[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
62027934SMark.Phalan@Sun.COM     if (loids[0] == NULL) {
62037934SMark.Phalan@Sun.COM 	free(loids);
62047934SMark.Phalan@Sun.COM 	goto cleanup;
62057934SMark.Phalan@Sun.COM     }
62067934SMark.Phalan@Sun.COM     retval = pkinit_copy_krb5_octet_data(&loids[0]->algorithm, &des3oid);
62077934SMark.Phalan@Sun.COM     if (retval) {
62087934SMark.Phalan@Sun.COM 	free(loids[0]);
62097934SMark.Phalan@Sun.COM 	free(loids);
62107934SMark.Phalan@Sun.COM 	goto cleanup;
62117934SMark.Phalan@Sun.COM     }
62127934SMark.Phalan@Sun.COM     loids[0]->parameters.length = 0;
62137934SMark.Phalan@Sun.COM     loids[0]->parameters.data = NULL;
62147934SMark.Phalan@Sun.COM 
62157934SMark.Phalan@Sun.COM     *oids = loids;
62167934SMark.Phalan@Sun.COM     retval = 0;
62177934SMark.Phalan@Sun.COM cleanup:
62187934SMark.Phalan@Sun.COM 
62197934SMark.Phalan@Sun.COM     return retval;
62207934SMark.Phalan@Sun.COM }
62217934SMark.Phalan@Sun.COM 
62227934SMark.Phalan@Sun.COM /* ARGSUSED */
62237934SMark.Phalan@Sun.COM krb5_error_code
62247934SMark.Phalan@Sun.COM create_krb5_trustedCertifiers(krb5_context context,
62257934SMark.Phalan@Sun.COM 			      pkinit_plg_crypto_context plg_cryptoctx,
62267934SMark.Phalan@Sun.COM 			      pkinit_req_crypto_context req_cryptoctx,
62277934SMark.Phalan@Sun.COM 			      pkinit_identity_crypto_context id_cryptoctx,
62287934SMark.Phalan@Sun.COM 			      krb5_external_principal_identifier *** ids)
62297934SMark.Phalan@Sun.COM {
62307934SMark.Phalan@Sun.COM 
62317934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
62327934SMark.Phalan@Sun.COM     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
62337934SMark.Phalan@Sun.COM 
62347934SMark.Phalan@Sun.COM     *ids = NULL;
62357934SMark.Phalan@Sun.COM     if (id_cryptoctx->trustedCAs == NULL)
62367934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
62377934SMark.Phalan@Sun.COM 
62387934SMark.Phalan@Sun.COM     return create_identifiers_from_stack(sk, ids);
62397934SMark.Phalan@Sun.COM 
62407934SMark.Phalan@Sun.COM }
62417934SMark.Phalan@Sun.COM 
62427934SMark.Phalan@Sun.COM /* ARGSUSED */
62437934SMark.Phalan@Sun.COM krb5_error_code
62447934SMark.Phalan@Sun.COM create_krb5_trustedCas(krb5_context context,
62457934SMark.Phalan@Sun.COM 		       pkinit_plg_crypto_context plg_cryptoctx,
62467934SMark.Phalan@Sun.COM 		       pkinit_req_crypto_context req_cryptoctx,
62477934SMark.Phalan@Sun.COM 		       pkinit_identity_crypto_context id_cryptoctx,
62487934SMark.Phalan@Sun.COM 		       int flag,
62497934SMark.Phalan@Sun.COM 		       krb5_trusted_ca *** ids)
62507934SMark.Phalan@Sun.COM {
62517934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
62527934SMark.Phalan@Sun.COM     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
62537934SMark.Phalan@Sun.COM     int i = 0, len = 0, sk_size = sk_X509_num(sk);
62547934SMark.Phalan@Sun.COM     krb5_trusted_ca **krb5_cas = NULL;
62557934SMark.Phalan@Sun.COM     X509 *x = NULL;
62567934SMark.Phalan@Sun.COM     char buf[DN_BUF_LEN];
62577934SMark.Phalan@Sun.COM     X509_NAME *xn = NULL;
62587934SMark.Phalan@Sun.COM     unsigned char *p = NULL;
62597934SMark.Phalan@Sun.COM     PKCS7_ISSUER_AND_SERIAL *is = NULL;
62607934SMark.Phalan@Sun.COM 
62617934SMark.Phalan@Sun.COM     *ids = NULL;
62627934SMark.Phalan@Sun.COM     if (id_cryptoctx->trustedCAs == NULL)
62637934SMark.Phalan@Sun.COM 	return KRB5KDC_ERR_PREAUTH_FAILED;
62647934SMark.Phalan@Sun.COM 
62657934SMark.Phalan@Sun.COM     krb5_cas = malloc((sk_size + 1) * sizeof(krb5_trusted_ca *));
62667934SMark.Phalan@Sun.COM     if (krb5_cas == NULL)
62677934SMark.Phalan@Sun.COM 	return ENOMEM;
62687934SMark.Phalan@Sun.COM     krb5_cas[sk_size] = NULL;
62697934SMark.Phalan@Sun.COM 
62707934SMark.Phalan@Sun.COM     for (i = 0; i < sk_size; i++) {
62717934SMark.Phalan@Sun.COM 	krb5_cas[i] = (krb5_trusted_ca *)malloc(sizeof(krb5_trusted_ca));
62727934SMark.Phalan@Sun.COM 	if (krb5_cas[i] == NULL)
62737934SMark.Phalan@Sun.COM 	    goto cleanup;
62747934SMark.Phalan@Sun.COM 	x = sk_X509_value(sk, i);
62757934SMark.Phalan@Sun.COM 
62767934SMark.Phalan@Sun.COM 	X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
62777934SMark.Phalan@Sun.COM 	pkiDebug("#%d cert= %s\n", i, buf);
62787934SMark.Phalan@Sun.COM 
62797934SMark.Phalan@Sun.COM 	switch (flag) {
62807934SMark.Phalan@Sun.COM 	    case choice_trusted_cas_principalName:
62817934SMark.Phalan@Sun.COM 		krb5_cas[i]->choice = choice_trusted_cas_principalName;
62827934SMark.Phalan@Sun.COM 		break;
62837934SMark.Phalan@Sun.COM 	    case choice_trusted_cas_caName:
62847934SMark.Phalan@Sun.COM 		krb5_cas[i]->choice = choice_trusted_cas_caName;
62857934SMark.Phalan@Sun.COM 		krb5_cas[i]->u.caName.data = NULL;
62867934SMark.Phalan@Sun.COM 		krb5_cas[i]->u.caName.length = 0;
62877934SMark.Phalan@Sun.COM 		xn = X509_get_subject_name(x);
62887934SMark.Phalan@Sun.COM 		len = i2d_X509_NAME(xn, NULL);
62897934SMark.Phalan@Sun.COM 		if ((p = krb5_cas[i]->u.caName.data =
62907934SMark.Phalan@Sun.COM 		    (unsigned char *)malloc((size_t) len)) == NULL)
62917934SMark.Phalan@Sun.COM 		    goto cleanup;
62927934SMark.Phalan@Sun.COM 		i2d_X509_NAME(xn, &p);
62937934SMark.Phalan@Sun.COM 		krb5_cas[i]->u.caName.length = len;
62947934SMark.Phalan@Sun.COM 		break;
62957934SMark.Phalan@Sun.COM 	    case choice_trusted_cas_issuerAndSerial:
62967934SMark.Phalan@Sun.COM 		krb5_cas[i]->choice = choice_trusted_cas_issuerAndSerial;
62977934SMark.Phalan@Sun.COM 		krb5_cas[i]->u.issuerAndSerial.data = NULL;
62987934SMark.Phalan@Sun.COM 		krb5_cas[i]->u.issuerAndSerial.length = 0;
62997934SMark.Phalan@Sun.COM 		is = PKCS7_ISSUER_AND_SERIAL_new();
63007934SMark.Phalan@Sun.COM 		X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
63017934SMark.Phalan@Sun.COM 		M_ASN1_INTEGER_free(is->serial);
63027934SMark.Phalan@Sun.COM 		is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
63037934SMark.Phalan@Sun.COM 		len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
63047934SMark.Phalan@Sun.COM 		if ((p = krb5_cas[i]->u.issuerAndSerial.data =
63057934SMark.Phalan@Sun.COM 		    (unsigned char *)malloc((size_t) len)) == NULL)
63067934SMark.Phalan@Sun.COM 		    goto cleanup;
63077934SMark.Phalan@Sun.COM 		i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
63087934SMark.Phalan@Sun.COM 		krb5_cas[i]->u.issuerAndSerial.length = len;
63097934SMark.Phalan@Sun.COM 		if (is != NULL) {
63107934SMark.Phalan@Sun.COM 		    if (is->issuer != NULL)
63117934SMark.Phalan@Sun.COM 			X509_NAME_free(is->issuer);
63127934SMark.Phalan@Sun.COM 		    if (is->serial != NULL)
63137934SMark.Phalan@Sun.COM 			ASN1_INTEGER_free(is->serial);
63147934SMark.Phalan@Sun.COM 		    free(is);
63157934SMark.Phalan@Sun.COM 		}
63167934SMark.Phalan@Sun.COM 		break;
63177934SMark.Phalan@Sun.COM 	    default: break;
63187934SMark.Phalan@Sun.COM 	}
63197934SMark.Phalan@Sun.COM     }
63207934SMark.Phalan@Sun.COM     retval = 0;
63217934SMark.Phalan@Sun.COM     *ids = krb5_cas;
63227934SMark.Phalan@Sun.COM cleanup:
63237934SMark.Phalan@Sun.COM     if (retval)
63247934SMark.Phalan@Sun.COM 	free_krb5_trusted_ca(&krb5_cas);
63257934SMark.Phalan@Sun.COM 
63267934SMark.Phalan@Sun.COM     return retval;
63277934SMark.Phalan@Sun.COM }
63287934SMark.Phalan@Sun.COM 
63297934SMark.Phalan@Sun.COM /* ARGSUSED */
63307934SMark.Phalan@Sun.COM krb5_error_code
63317934SMark.Phalan@Sun.COM create_issuerAndSerial(krb5_context context,
63327934SMark.Phalan@Sun.COM 		       pkinit_plg_crypto_context plg_cryptoctx,
63337934SMark.Phalan@Sun.COM 		       pkinit_req_crypto_context req_cryptoctx,
63347934SMark.Phalan@Sun.COM 		       pkinit_identity_crypto_context id_cryptoctx,
63357934SMark.Phalan@Sun.COM 		       unsigned char **out,
63367934SMark.Phalan@Sun.COM 		       unsigned int *out_len)
63377934SMark.Phalan@Sun.COM {
63387934SMark.Phalan@Sun.COM     unsigned char *p = NULL;
63397934SMark.Phalan@Sun.COM     PKCS7_ISSUER_AND_SERIAL *is = NULL;
63407934SMark.Phalan@Sun.COM     int len = 0;
63417934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
63427934SMark.Phalan@Sun.COM     X509 *cert = req_cryptoctx->received_cert;
63437934SMark.Phalan@Sun.COM 
63447934SMark.Phalan@Sun.COM     *out = NULL;
63457934SMark.Phalan@Sun.COM     *out_len = 0;
63467934SMark.Phalan@Sun.COM     if (req_cryptoctx->received_cert == NULL)
63477934SMark.Phalan@Sun.COM 	return 0;
63487934SMark.Phalan@Sun.COM 
63497934SMark.Phalan@Sun.COM     is = PKCS7_ISSUER_AND_SERIAL_new();
63507934SMark.Phalan@Sun.COM     X509_NAME_set(&is->issuer, X509_get_issuer_name(cert));
63517934SMark.Phalan@Sun.COM     M_ASN1_INTEGER_free(is->serial);
63527934SMark.Phalan@Sun.COM     is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(cert));
63537934SMark.Phalan@Sun.COM     len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
63547934SMark.Phalan@Sun.COM     if ((p = *out = (unsigned char *)malloc((size_t) len)) == NULL)
63557934SMark.Phalan@Sun.COM 	goto cleanup;
63567934SMark.Phalan@Sun.COM     i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
63577934SMark.Phalan@Sun.COM     *out_len = len;
63587934SMark.Phalan@Sun.COM     retval = 0;
63597934SMark.Phalan@Sun.COM 
63607934SMark.Phalan@Sun.COM cleanup:
63617934SMark.Phalan@Sun.COM     X509_NAME_free(is->issuer);
63627934SMark.Phalan@Sun.COM     ASN1_INTEGER_free(is->serial);
63637934SMark.Phalan@Sun.COM     free(is);
63647934SMark.Phalan@Sun.COM 
63657934SMark.Phalan@Sun.COM     return retval;
63667934SMark.Phalan@Sun.COM }
63677934SMark.Phalan@Sun.COM 
63687934SMark.Phalan@Sun.COM static int
63697934SMark.Phalan@Sun.COM pkcs7_decrypt(krb5_context context,
63707934SMark.Phalan@Sun.COM 	      pkinit_identity_crypto_context id_cryptoctx,
63717934SMark.Phalan@Sun.COM 	      PKCS7 *p7,
63727934SMark.Phalan@Sun.COM 	      BIO *data)
63737934SMark.Phalan@Sun.COM {
63747934SMark.Phalan@Sun.COM     BIO *tmpmem = NULL;
63757934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
63767934SMark.Phalan@Sun.COM     int i = 0;
63777934SMark.Phalan@Sun.COM     char buf[4096];
63787934SMark.Phalan@Sun.COM 
63797934SMark.Phalan@Sun.COM     if(p7 == NULL)
63807934SMark.Phalan@Sun.COM 	return 0;
63817934SMark.Phalan@Sun.COM 
63827934SMark.Phalan@Sun.COM     if(!PKCS7_type_is_enveloped(p7)) {
63837934SMark.Phalan@Sun.COM 	pkiDebug("wrong pkcs7 content type\n");
63847934SMark.Phalan@Sun.COM 	return 0;
63857934SMark.Phalan@Sun.COM     }
63867934SMark.Phalan@Sun.COM 
63877934SMark.Phalan@Sun.COM     if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) {
63887934SMark.Phalan@Sun.COM 	pkiDebug("unable to decrypt pkcs7 object\n");
63897934SMark.Phalan@Sun.COM 	return 0;
63907934SMark.Phalan@Sun.COM     }
63917934SMark.Phalan@Sun.COM /* Solaris Kerberos: Suppress sun studio compiler warning */
63927934SMark.Phalan@Sun.COM #pragma error_messages (off, E_END_OF_LOOP_CODE_NOT_REACHED)
63937934SMark.Phalan@Sun.COM     for(;;) {
63947934SMark.Phalan@Sun.COM 	i = BIO_read(tmpmem, buf, sizeof(buf));
63957934SMark.Phalan@Sun.COM 	if (i <= 0) break;
63967934SMark.Phalan@Sun.COM 	BIO_write(data, buf, i);
63977934SMark.Phalan@Sun.COM 	BIO_free_all(tmpmem);
63987934SMark.Phalan@Sun.COM 	return 1;
63997934SMark.Phalan@Sun.COM     }
64007934SMark.Phalan@Sun.COM #pragma error_messages (default, E_END_OF_LOOP_CODE_NOT_REACHED)
64017934SMark.Phalan@Sun.COM 
64027934SMark.Phalan@Sun.COM     return 0;
64037934SMark.Phalan@Sun.COM }
64047934SMark.Phalan@Sun.COM 
64057934SMark.Phalan@Sun.COM krb5_error_code
64067934SMark.Phalan@Sun.COM pkinit_process_td_trusted_certifiers(
64077934SMark.Phalan@Sun.COM     krb5_context context,
64087934SMark.Phalan@Sun.COM     pkinit_plg_crypto_context plg_cryptoctx,
64097934SMark.Phalan@Sun.COM     pkinit_req_crypto_context req_cryptoctx,
64107934SMark.Phalan@Sun.COM     pkinit_identity_crypto_context id_cryptoctx,
64117934SMark.Phalan@Sun.COM     krb5_external_principal_identifier **krb5_trusted_certifiers,
64127934SMark.Phalan@Sun.COM     int td_type)
64137934SMark.Phalan@Sun.COM {
64147934SMark.Phalan@Sun.COM     krb5_error_code retval = ENOMEM;
64157934SMark.Phalan@Sun.COM     STACK_OF(X509_NAME) *sk_xn = NULL;
64167934SMark.Phalan@Sun.COM     X509_NAME *xn = NULL;
64177934SMark.Phalan@Sun.COM     PKCS7_ISSUER_AND_SERIAL *is = NULL;
64187934SMark.Phalan@Sun.COM     ASN1_OCTET_STRING *id = NULL;
64197934SMark.Phalan@Sun.COM     const unsigned char *p = NULL;
64207934SMark.Phalan@Sun.COM     char buf[DN_BUF_LEN];
64217934SMark.Phalan@Sun.COM     int i = 0;
64227934SMark.Phalan@Sun.COM 
64237934SMark.Phalan@Sun.COM     if (td_type == TD_TRUSTED_CERTIFIERS)
64247934SMark.Phalan@Sun.COM 	pkiDebug("received trusted certifiers\n");
64257934SMark.Phalan@Sun.COM     else
64267934SMark.Phalan@Sun.COM 	pkiDebug("received invalid certificate\n");
64277934SMark.Phalan@Sun.COM 
64287934SMark.Phalan@Sun.COM     sk_xn = sk_X509_NAME_new_null();
64297934SMark.Phalan@Sun.COM     while(krb5_trusted_certifiers[i] != NULL) {
64307934SMark.Phalan@Sun.COM 	if (krb5_trusted_certifiers[i]->subjectName.data != NULL) {
64317934SMark.Phalan@Sun.COM 	    p = krb5_trusted_certifiers[i]->subjectName.data;
64327934SMark.Phalan@Sun.COM 	    xn = d2i_X509_NAME(NULL, &p,
64337934SMark.Phalan@Sun.COM 		(int)krb5_trusted_certifiers[i]->subjectName.length);
64347934SMark.Phalan@Sun.COM 	    if (xn == NULL)
64357934SMark.Phalan@Sun.COM 		goto cleanup;
64367934SMark.Phalan@Sun.COM 	    X509_NAME_oneline(xn, buf, sizeof(buf));
64377934SMark.Phalan@Sun.COM 	    if (td_type == TD_TRUSTED_CERTIFIERS)
64387934SMark.Phalan@Sun.COM 		pkiDebug("#%d cert = %s is trusted by kdc\n", i, buf);
64397934SMark.Phalan@Sun.COM 	    else
64407934SMark.Phalan@Sun.COM 		pkiDebug("#%d cert = %s is invalid\n", i, buf);
64417934SMark.Phalan@Sun.COM 		sk_X509_NAME_push(sk_xn, xn);
64427934SMark.Phalan@Sun.COM 	}
64437934SMark.Phalan@Sun.COM 
64447934SMark.Phalan@Sun.COM 	if (krb5_trusted_certifiers[i]->issuerAndSerialNumber.data != NULL) {
64457934SMark.Phalan@Sun.COM 	    p = krb5_trusted_certifiers[i]->issuerAndSerialNumber.data;
64467934SMark.Phalan@Sun.COM 	    is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p,
64477934SMark.Phalan@Sun.COM 		(int)krb5_trusted_certifiers[i]->issuerAndSerialNumber.length);
64487934SMark.Phalan@Sun.COM 	    if (is == NULL)
64497934SMark.Phalan@Sun.COM 		goto cleanup;
64507934SMark.Phalan@Sun.COM 	    X509_NAME_oneline(is->issuer, buf, sizeof(buf));
64517934SMark.Phalan@Sun.COM 	    if (td_type == TD_TRUSTED_CERTIFIERS)
64527934SMark.Phalan@Sun.COM 		pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
64537934SMark.Phalan@Sun.COM 			 buf, ASN1_INTEGER_get(is->serial));
64547934SMark.Phalan@Sun.COM 	    else
64557934SMark.Phalan@Sun.COM 		pkiDebug("#%d issuer = %s serial = %ld is invalid\n", i, buf,
64567934SMark.Phalan@Sun.COM 			 ASN1_INTEGER_get(is->serial));
64577934SMark.Phalan@Sun.COM 	    PKCS7_ISSUER_AND_SERIAL_free(is);
64587934SMark.Phalan@Sun.COM 	}
64597934SMark.Phalan@Sun.COM 
64607934SMark.Phalan@Sun.COM 	if (krb5_trusted_certifiers[i]->subjectKeyIdentifier.data != NULL) {
64617934SMark.Phalan@Sun.COM 	    p = krb5_trusted_certifiers[i]->subjectKeyIdentifier.data;
64627934SMark.Phalan@Sun.COM 	    id = d2i_ASN1_OCTET_STRING(NULL, &p,
64637934SMark.Phalan@Sun.COM 		(int)krb5_trusted_certifiers[i]->subjectKeyIdentifier.length);
64647934SMark.Phalan@Sun.COM 	    if (id == NULL)
64657934SMark.Phalan@Sun.COM 		goto cleanup;
64667934SMark.Phalan@Sun.COM 	    /* XXX */
64677934SMark.Phalan@Sun.COM 	    ASN1_OCTET_STRING_free(id);
64687934SMark.Phalan@Sun.COM 	}
64697934SMark.Phalan@Sun.COM 	i++;
64707934SMark.Phalan@Sun.COM     }
64717934SMark.Phalan@Sun.COM     /* XXX Since we not doing anything with received trusted certifiers
64727934SMark.Phalan@Sun.COM      * return an error. this is the place where we can pick a different
64737934SMark.Phalan@Sun.COM      * client certificate based on the information in td_trusted_certifiers
64747934SMark.Phalan@Sun.COM      */
64757934SMark.Phalan@Sun.COM     retval = KRB5KDC_ERR_PREAUTH_FAILED;
64767934SMark.Phalan@Sun.COM cleanup:
64777934SMark.Phalan@Sun.COM     if (sk_xn != NULL)
64787934SMark.Phalan@Sun.COM 	sk_X509_NAME_pop_free(sk_xn, X509_NAME_free);
64797934SMark.Phalan@Sun.COM 
64807934SMark.Phalan@Sun.COM     return retval;
64817934SMark.Phalan@Sun.COM }
64827934SMark.Phalan@Sun.COM 
64837934SMark.Phalan@Sun.COM static BIO *
64847934SMark.Phalan@Sun.COM pkcs7_dataDecode(krb5_context context,
64857934SMark.Phalan@Sun.COM 		 pkinit_identity_crypto_context id_cryptoctx,
64867934SMark.Phalan@Sun.COM 		 PKCS7 *p7)
64877934SMark.Phalan@Sun.COM {
64887934SMark.Phalan@Sun.COM     int i = 0;
64897934SMark.Phalan@Sun.COM     unsigned int jj = 0, tmp_len = 0;
64907934SMark.Phalan@Sun.COM     BIO *out=NULL,*etmp=NULL,*bio=NULL;
64917934SMark.Phalan@Sun.COM     unsigned char *tmp=NULL;
64927934SMark.Phalan@Sun.COM     ASN1_OCTET_STRING *data_body=NULL;
64937934SMark.Phalan@Sun.COM     const EVP_CIPHER *evp_cipher=NULL;
64947934SMark.Phalan@Sun.COM     EVP_CIPHER_CTX *evp_ctx=NULL;
64957934SMark.Phalan@Sun.COM     X509_ALGOR *enc_alg=NULL;
64967934SMark.Phalan@Sun.COM     STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
64977934SMark.Phalan@Sun.COM /* Solaris Kerberos: Not used */
64987934SMark.Phalan@Sun.COM #if 0
64997934SMark.Phalan@Sun.COM     X509_ALGOR *xalg=NULL;
65007934SMark.Phalan@Sun.COM #endif
65017934SMark.Phalan@Sun.COM     PKCS7_RECIP_INFO *ri=NULL;
65027934SMark.Phalan@Sun.COM     X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
65037934SMark.Phalan@Sun.COM 	id_cryptoctx->cert_index);
65047934SMark.Phalan@Sun.COM 
65057934SMark.Phalan@Sun.COM     p7->state=PKCS7_S_HEADER;
65067934SMark.Phalan@Sun.COM 
65077934SMark.Phalan@Sun.COM     rsk=p7->d.enveloped->recipientinfo;
65087934SMark.Phalan@Sun.COM     enc_alg=p7->d.enveloped->enc_data->algorithm;
65097934SMark.Phalan@Sun.COM     data_body=p7->d.enveloped->enc_data->enc_data;
65107934SMark.Phalan@Sun.COM     evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
65117934SMark.Phalan@Sun.COM     if (evp_cipher == NULL) {
65127934SMark.Phalan@Sun.COM 	PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
65137934SMark.Phalan@Sun.COM 	goto cleanup;
65147934SMark.Phalan@Sun.COM     }
65157934SMark.Phalan@Sun.COM /* Solaris Kerberos: Not used */
65167934SMark.Phalan@Sun.COM #if 0
65177934SMark.Phalan@Sun.COM     xalg=p7->d.enveloped->enc_data->algorithm;
65187934SMark.Phalan@Sun.COM #endif
65197934SMark.Phalan@Sun.COM 
65207934SMark.Phalan@Sun.COM     if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
65217934SMark.Phalan@Sun.COM 	PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
65227934SMark.Phalan@Sun.COM 	goto cleanup;
65237934SMark.Phalan@Sun.COM     }
65247934SMark.Phalan@Sun.COM 
65257934SMark.Phalan@Sun.COM     /* It was encrypted, we need to decrypt the secret key
65267934SMark.Phalan@Sun.COM      * with the private key */
65277934SMark.Phalan@Sun.COM 
65287934SMark.Phalan@Sun.COM     /* Find the recipientInfo which matches the passed certificate
65297934SMark.Phalan@Sun.COM      * (if any)
65307934SMark.Phalan@Sun.COM      */
65317934SMark.Phalan@Sun.COM 
65327934SMark.Phalan@Sun.COM     if (cert) {
65337934SMark.Phalan@Sun.COM 	for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
65347934SMark.Phalan@Sun.COM 	    int tmp_ret = 0;
65357934SMark.Phalan@Sun.COM 	    ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
65367934SMark.Phalan@Sun.COM 	    tmp_ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
65377934SMark.Phalan@Sun.COM 				    cert->cert_info->issuer);
65387934SMark.Phalan@Sun.COM 	    if (!tmp_ret) {
65397934SMark.Phalan@Sun.COM 		tmp_ret = M_ASN1_INTEGER_cmp(cert->cert_info->serialNumber,
65407934SMark.Phalan@Sun.COM 					     ri->issuer_and_serial->serial);
65417934SMark.Phalan@Sun.COM 		if (!tmp_ret)
65427934SMark.Phalan@Sun.COM 		    break;
65437934SMark.Phalan@Sun.COM 	    }
65447934SMark.Phalan@Sun.COM 	    ri=NULL;
65457934SMark.Phalan@Sun.COM 	}
65467934SMark.Phalan@Sun.COM 	if (ri == NULL) {
65477934SMark.Phalan@Sun.COM 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE,
65487934SMark.Phalan@Sun.COM 		     PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
65497934SMark.Phalan@Sun.COM 	    goto cleanup;
65507934SMark.Phalan@Sun.COM 	}
65517934SMark.Phalan@Sun.COM 
65527934SMark.Phalan@Sun.COM     }
65537934SMark.Phalan@Sun.COM 
65547934SMark.Phalan@Sun.COM     /* If we haven't got a certificate try each ri in turn */
65557934SMark.Phalan@Sun.COM 
65567934SMark.Phalan@Sun.COM     if (cert == NULL) {
65577934SMark.Phalan@Sun.COM 	for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
65587934SMark.Phalan@Sun.COM 	    ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
65597934SMark.Phalan@Sun.COM 	    jj = pkinit_decode_data(context, id_cryptoctx,
65607934SMark.Phalan@Sun.COM 		M_ASN1_STRING_data(ri->enc_key),
65617934SMark.Phalan@Sun.COM 		(unsigned int) M_ASN1_STRING_length(ri->enc_key),
65627934SMark.Phalan@Sun.COM 		&tmp, &tmp_len);
65637934SMark.Phalan@Sun.COM 	    if (jj) {
65647934SMark.Phalan@Sun.COM 		PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
65657934SMark.Phalan@Sun.COM 		goto cleanup;
65667934SMark.Phalan@Sun.COM 	    }
65677934SMark.Phalan@Sun.COM 
65687934SMark.Phalan@Sun.COM 	    if (!jj && tmp_len > 0) {
65697934SMark.Phalan@Sun.COM 		jj = tmp_len;
65707934SMark.Phalan@Sun.COM 		break;
65717934SMark.Phalan@Sun.COM 	    }
65727934SMark.Phalan@Sun.COM 
65737934SMark.Phalan@Sun.COM 	    ERR_clear_error();
65747934SMark.Phalan@Sun.COM 	    ri = NULL;
65757934SMark.Phalan@Sun.COM 	}
65767934SMark.Phalan@Sun.COM 
65777934SMark.Phalan@Sun.COM 	if (ri == NULL) {
65787934SMark.Phalan@Sun.COM 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_KEY);
65797934SMark.Phalan@Sun.COM 	    goto cleanup;
65807934SMark.Phalan@Sun.COM 	}
65817934SMark.Phalan@Sun.COM     }
65827934SMark.Phalan@Sun.COM     else {
65837934SMark.Phalan@Sun.COM 	jj = pkinit_decode_data(context, id_cryptoctx,
65847934SMark.Phalan@Sun.COM 	    M_ASN1_STRING_data(ri->enc_key),
65857934SMark.Phalan@Sun.COM 	    (unsigned int) M_ASN1_STRING_length(ri->enc_key),
65867934SMark.Phalan@Sun.COM 	    &tmp, &tmp_len);
65877934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: tmp_len is unsigned. Cannot be < 0 */
65887934SMark.Phalan@Sun.COM 	if (jj || tmp_len == 0) {
65897934SMark.Phalan@Sun.COM 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
65907934SMark.Phalan@Sun.COM 	    goto cleanup;
65917934SMark.Phalan@Sun.COM 	}
65927934SMark.Phalan@Sun.COM 	jj = tmp_len;
65937934SMark.Phalan@Sun.COM     }
65947934SMark.Phalan@Sun.COM 
65957934SMark.Phalan@Sun.COM     evp_ctx=NULL;
65967934SMark.Phalan@Sun.COM     BIO_get_cipher_ctx(etmp,&evp_ctx);
65977934SMark.Phalan@Sun.COM     if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
65987934SMark.Phalan@Sun.COM 	goto cleanup;
65997934SMark.Phalan@Sun.COM     if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
66007934SMark.Phalan@Sun.COM 	goto cleanup;
66017934SMark.Phalan@Sun.COM 
66027934SMark.Phalan@Sun.COM     if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
66037934SMark.Phalan@Sun.COM 	/* Some S/MIME clients don't use the same key
66047934SMark.Phalan@Sun.COM 	 * and effective key length. The key length is
66057934SMark.Phalan@Sun.COM 	 * determined by the size of the decrypted RSA key.
66067934SMark.Phalan@Sun.COM 	 */
66077934SMark.Phalan@Sun.COM 	if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)jj)) {
66087934SMark.Phalan@Sun.COM 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE,
66097934SMark.Phalan@Sun.COM 		     PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH);
66107934SMark.Phalan@Sun.COM 	    goto cleanup;
66117934SMark.Phalan@Sun.COM 	}
66127934SMark.Phalan@Sun.COM     }
66137934SMark.Phalan@Sun.COM     if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
66147934SMark.Phalan@Sun.COM 	goto cleanup;
66157934SMark.Phalan@Sun.COM 
66167934SMark.Phalan@Sun.COM     OPENSSL_cleanse(tmp,jj);
66177934SMark.Phalan@Sun.COM 
66187934SMark.Phalan@Sun.COM     if (out == NULL)
66197934SMark.Phalan@Sun.COM 	out=etmp;
66207934SMark.Phalan@Sun.COM     else
66217934SMark.Phalan@Sun.COM 	BIO_push(out,etmp);
66227934SMark.Phalan@Sun.COM     etmp=NULL;
66237934SMark.Phalan@Sun.COM 
66247934SMark.Phalan@Sun.COM     if (data_body->length > 0)
66257934SMark.Phalan@Sun.COM 	bio = BIO_new_mem_buf(data_body->data, data_body->length);
66267934SMark.Phalan@Sun.COM     else {
66277934SMark.Phalan@Sun.COM 	bio=BIO_new(BIO_s_mem());
66287934SMark.Phalan@Sun.COM 	BIO_set_mem_eof_return(bio,0);
66297934SMark.Phalan@Sun.COM     }
66307934SMark.Phalan@Sun.COM     BIO_push(out,bio);
66317934SMark.Phalan@Sun.COM     bio=NULL;
66327934SMark.Phalan@Sun.COM 
66337934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
66347934SMark.Phalan@Sun.COM     goto out;
66357934SMark.Phalan@Sun.COM 
66367934SMark.Phalan@Sun.COM cleanup:
66377934SMark.Phalan@Sun.COM 	if (out != NULL) BIO_free_all(out);
66387934SMark.Phalan@Sun.COM 	if (etmp != NULL) BIO_free_all(etmp);
66397934SMark.Phalan@Sun.COM 	if (bio != NULL) BIO_free_all(bio);
66407934SMark.Phalan@Sun.COM 	out=NULL;
66417934SMark.Phalan@Sun.COM 
66427934SMark.Phalan@Sun.COM out:
66437934SMark.Phalan@Sun.COM     if (tmp != NULL)
66447934SMark.Phalan@Sun.COM 	free(tmp);
66457934SMark.Phalan@Sun.COM 
66467934SMark.Phalan@Sun.COM     return(out);
66477934SMark.Phalan@Sun.COM }
66487934SMark.Phalan@Sun.COM 
66497934SMark.Phalan@Sun.COM static krb5_error_code
66507934SMark.Phalan@Sun.COM der_decode_data(unsigned char *data, long data_len,
66517934SMark.Phalan@Sun.COM 		unsigned char **out, long *out_len)
66527934SMark.Phalan@Sun.COM {
66537934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
66547934SMark.Phalan@Sun.COM     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
66557934SMark.Phalan@Sun.COM     ASN1_OCTET_STRING *s = NULL;
66567934SMark.Phalan@Sun.COM     const unsigned char *p = data;
66577934SMark.Phalan@Sun.COM 
66587934SMark.Phalan@Sun.COM     if ((s = d2i_ASN1_BIT_STRING(NULL, &p, data_len)) == NULL)
66597934SMark.Phalan@Sun.COM 	goto cleanup;
66607934SMark.Phalan@Sun.COM     *out_len = s->length;
66617934SMark.Phalan@Sun.COM     if ((*out = (unsigned char *) malloc((size_t) *out_len + 1)) == NULL) {
66627934SMark.Phalan@Sun.COM 	retval = ENOMEM;
66637934SMark.Phalan@Sun.COM 	goto cleanup;
66647934SMark.Phalan@Sun.COM     }
66657934SMark.Phalan@Sun.COM     (void) memcpy(*out, s->data, (size_t) s->length);
66667934SMark.Phalan@Sun.COM     (*out)[s->length] = '\0';
66677934SMark.Phalan@Sun.COM 
66687934SMark.Phalan@Sun.COM     retval = 0;
66697934SMark.Phalan@Sun.COM   cleanup:
66707934SMark.Phalan@Sun.COM     if (s != NULL)
66717934SMark.Phalan@Sun.COM 	ASN1_OCTET_STRING_free(s);
66727934SMark.Phalan@Sun.COM 
66737934SMark.Phalan@Sun.COM     return retval;
66747934SMark.Phalan@Sun.COM }
66757934SMark.Phalan@Sun.COM 
66767934SMark.Phalan@Sun.COM 
66777934SMark.Phalan@Sun.COM #ifdef DEBUG_DH
66787934SMark.Phalan@Sun.COM static void
66797934SMark.Phalan@Sun.COM print_dh(DH * dh, char *msg)
66807934SMark.Phalan@Sun.COM {
66817934SMark.Phalan@Sun.COM     BIO *bio_err = NULL;
66827934SMark.Phalan@Sun.COM 
66837934SMark.Phalan@Sun.COM     bio_err = BIO_new(BIO_s_file());
66847934SMark.Phalan@Sun.COM     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
66857934SMark.Phalan@Sun.COM 
66867934SMark.Phalan@Sun.COM     if (msg)
66877934SMark.Phalan@Sun.COM 	BIO_puts(bio_err, (const char *)msg);
66887934SMark.Phalan@Sun.COM     if (dh)
66897934SMark.Phalan@Sun.COM 	DHparams_print(bio_err, dh);
66907934SMark.Phalan@Sun.COM 
66917934SMark.Phalan@Sun.COM     BN_print(bio_err, dh->q);
66927934SMark.Phalan@Sun.COM     BIO_puts(bio_err, (const char *)"\n");
66937934SMark.Phalan@Sun.COM     BIO_free(bio_err);
66947934SMark.Phalan@Sun.COM 
66957934SMark.Phalan@Sun.COM }
66967934SMark.Phalan@Sun.COM 
66977934SMark.Phalan@Sun.COM static void
66987934SMark.Phalan@Sun.COM print_pubkey(BIGNUM * key, char *msg)
66997934SMark.Phalan@Sun.COM {
67007934SMark.Phalan@Sun.COM     BIO *bio_err = NULL;
67017934SMark.Phalan@Sun.COM 
67027934SMark.Phalan@Sun.COM     bio_err = BIO_new(BIO_s_file());
67037934SMark.Phalan@Sun.COM     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
67047934SMark.Phalan@Sun.COM 
67057934SMark.Phalan@Sun.COM     if (msg)
67067934SMark.Phalan@Sun.COM 	BIO_puts(bio_err, (const char *)msg);
67077934SMark.Phalan@Sun.COM     if (key)
67087934SMark.Phalan@Sun.COM 	BN_print(bio_err, key);
67097934SMark.Phalan@Sun.COM     BIO_puts(bio_err, "\n");
67107934SMark.Phalan@Sun.COM 
67117934SMark.Phalan@Sun.COM     BIO_free(bio_err);
67127934SMark.Phalan@Sun.COM 
67137934SMark.Phalan@Sun.COM }
67147934SMark.Phalan@Sun.COM #endif
67157934SMark.Phalan@Sun.COM 
67167934SMark.Phalan@Sun.COM /*
67177934SMark.Phalan@Sun.COM  * Solaris Kerberos:
67187934SMark.Phalan@Sun.COM  * Error message generation has changed so gettext() can be used
67197934SMark.Phalan@Sun.COM  */
67207934SMark.Phalan@Sun.COM #if 0
67217934SMark.Phalan@Sun.COM static char *
67227934SMark.Phalan@Sun.COM pkinit_pkcs11_code_to_text(int err)
67237934SMark.Phalan@Sun.COM {
67247934SMark.Phalan@Sun.COM     int i;
67257934SMark.Phalan@Sun.COM     static char uc[64];
67267934SMark.Phalan@Sun.COM 
67277934SMark.Phalan@Sun.COM     for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
67287934SMark.Phalan@Sun.COM 	if (pkcs11_errstrings[i].code == err)
67297934SMark.Phalan@Sun.COM 	    break;
67307934SMark.Phalan@Sun.COM     if (pkcs11_errstrings[i].text != NULL)
67317934SMark.Phalan@Sun.COM 	return (pkcs11_errstrings[i].text);
67327934SMark.Phalan@Sun.COM     snprintf(uc, 64, gettext("unknown code 0x%x"), err);
67337934SMark.Phalan@Sun.COM     return (uc);
67347934SMark.Phalan@Sun.COM }
67357934SMark.Phalan@Sun.COM #endif
67367934SMark.Phalan@Sun.COM 
67377934SMark.Phalan@Sun.COM static char *
67387934SMark.Phalan@Sun.COM pkinit_pkcs11_code_to_text(int err) {
67397934SMark.Phalan@Sun.COM 	return pkcs11_error_table(err);
67407934SMark.Phalan@Sun.COM }
6741