1 /*
   2  * COPYRIGHT (C) 2006,2007
   3  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
   4  * ALL RIGHTS RESERVED
   5  *
   6  * Permission is granted to use, copy, create derivative works
   7  * and redistribute this software and such derivative works
   8  * for any purpose, so long as the name of The University of
   9  * Michigan is not used in any advertising or publicity
  10  * pertaining to the use of distribution of this software
  11  * without specific, written prior authorization.  If the
  12  * above copyright notice or any other identification of the
  13  * University of Michigan is included in any copy of any
  14  * portion of this software, then the disclaimer below must
  15  * also be included.
  16  *
  17  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
  18  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
  19  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
  20  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
  21  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
  22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
  23  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
  24  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
  25  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
  26  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
  27  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
  28  * SUCH DAMAGES.
  29  */
  30 
  31 /*
  32  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  33  * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
  34  * Copyright 2015 RackTop Systems.
  35  */
  36 
  37 #include <errno.h>
  38 #include <string.h>
  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 #include <dlfcn.h>
  42 #include <unistd.h>
  43 #include <dirent.h>
  44 
  45 
  46 /* Solaris Kerberos */
  47 #include <libintl.h>
  48 #include <assert.h>
  49 #include <security/pam_appl.h>
  50 #include <ctype.h>
  51 #include "k5-int.h"
  52 #include <ctype.h>
  53 
  54 /*
  55  * Q: What is this SILLYDECRYPT stuff about?
  56  * A: When using the ActivCard Linux pkcs11 library (v2.0.1),
  57  *    the decrypt function fails.  By inserting an extra
  58  *    function call, which serves nothing but to change the
  59  *    stack, we were able to work around the issue.  If the
  60  *    ActivCard library is fixed in the future, this
  61  *    definition and related code can be removed.
  62  */
  63 #define SILLYDECRYPT
  64 
  65 #include "pkinit_crypto_openssl.h"
  66 
  67 /*
  68  * Solaris Kerberos:
  69  * Changed to a switch statement so gettext() can be used
  70  * for internationization.
  71  * Use defined constants rather than raw numbers for error codes.
  72  */
  73 static char *
  74 pkcs11_error_table(short code) {
  75         switch (code) {
  76             case CKR_OK:
  77                 return (gettext("ok"));
  78             case CKR_CANCEL:
  79                 return (gettext("cancel"));
  80             case CKR_HOST_MEMORY:
  81                 return (gettext("host memory"));
  82             case CKR_SLOT_ID_INVALID:
  83                 return (gettext("slot id invalid"));
  84             case CKR_GENERAL_ERROR:
  85                 return (gettext("general error"));
  86             case CKR_FUNCTION_FAILED:
  87                 return (gettext("function failed"));
  88             case CKR_ARGUMENTS_BAD:
  89                 return (gettext("arguments bad"));
  90             case CKR_NO_EVENT:
  91                 return (gettext("no event"));
  92             case CKR_NEED_TO_CREATE_THREADS:
  93                 return (gettext("need to create threads"));
  94             case CKR_CANT_LOCK:
  95                 return (gettext("cant lock"));
  96             case CKR_ATTRIBUTE_READ_ONLY:
  97                 return (gettext("attribute read only"));
  98             case CKR_ATTRIBUTE_SENSITIVE:
  99                 return (gettext("attribute sensitive"));
 100             case CKR_ATTRIBUTE_TYPE_INVALID:
 101                 return (gettext("attribute type invalid"));
 102             case CKR_ATTRIBUTE_VALUE_INVALID:
 103                 return (gettext("attribute value invalid"));
 104             case CKR_DATA_INVALID:
 105                 return (gettext("data invalid"));
 106             case CKR_DATA_LEN_RANGE:
 107                 return (gettext("data len range"));
 108             case CKR_DEVICE_ERROR:
 109                 return (gettext("device error"));
 110             case CKR_DEVICE_MEMORY:
 111                 return (gettext("device memory"));
 112             case CKR_DEVICE_REMOVED:
 113                 return (gettext("device removed"));
 114             case CKR_ENCRYPTED_DATA_INVALID:
 115                 return (gettext("encrypted data invalid"));
 116             case CKR_ENCRYPTED_DATA_LEN_RANGE:
 117                 return (gettext("encrypted data len range"));
 118             case CKR_FUNCTION_CANCELED:
 119                 return (gettext("function canceled"));
 120             case CKR_FUNCTION_NOT_PARALLEL:
 121                 return (gettext("function not parallel"));
 122             case CKR_FUNCTION_NOT_SUPPORTED:
 123                 return (gettext("function not supported"));
 124             case CKR_KEY_HANDLE_INVALID:
 125                 return (gettext("key handle invalid"));
 126             case CKR_KEY_SIZE_RANGE:
 127                 return (gettext("key size range"));
 128             case CKR_KEY_TYPE_INCONSISTENT:
 129                 return (gettext("key type inconsistent"));
 130             case CKR_KEY_NOT_NEEDED:
 131                 return (gettext("key not needed"));
 132             case CKR_KEY_CHANGED:
 133                 return (gettext("key changed"));
 134             case CKR_KEY_NEEDED:
 135                 return (gettext("key needed"));
 136             case CKR_KEY_INDIGESTIBLE:
 137                 return (gettext("key indigestible"));
 138             case CKR_KEY_FUNCTION_NOT_PERMITTED:
 139                 return (gettext("key function not permitted"));
 140             case CKR_KEY_NOT_WRAPPABLE:
 141                 return (gettext("key not wrappable"));
 142             case CKR_KEY_UNEXTRACTABLE:
 143                 return (gettext("key unextractable"));
 144             case CKR_MECHANISM_INVALID:
 145                 return (gettext("mechanism invalid"));
 146             case CKR_MECHANISM_PARAM_INVALID:
 147                 return (gettext("mechanism param invalid"));
 148             case CKR_OBJECT_HANDLE_INVALID:
 149                 return (gettext("object handle invalid"));
 150             case CKR_OPERATION_ACTIVE:
 151                 return (gettext("operation active"));
 152             case CKR_OPERATION_NOT_INITIALIZED:
 153                 return (gettext("operation not initialized"));
 154             case CKR_PIN_INCORRECT:
 155                 return (gettext("pin incorrect"));
 156             case CKR_PIN_INVALID:
 157                 return (gettext("pin invalid"));
 158             case CKR_PIN_LEN_RANGE:
 159                 return (gettext("pin len range"));
 160             case CKR_PIN_EXPIRED:
 161                 return (gettext("pin expired"));
 162             case CKR_PIN_LOCKED:
 163                 return (gettext("pin locked"));
 164             case CKR_SESSION_CLOSED:
 165                 return (gettext("session closed"));
 166             case CKR_SESSION_COUNT:
 167                 return (gettext("session count"));
 168             case CKR_SESSION_HANDLE_INVALID:
 169                 return (gettext("session handle invalid"));
 170             case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
 171                 return (gettext("session parallel not supported"));
 172             case CKR_SESSION_READ_ONLY:
 173                 return (gettext("session read only"));
 174             case CKR_SESSION_EXISTS:
 175                 return (gettext("session exists"));
 176             case CKR_SESSION_READ_ONLY_EXISTS:
 177                 return (gettext("session read only exists"));
 178             case CKR_SESSION_READ_WRITE_SO_EXISTS:
 179                 return (gettext("session read write so exists"));
 180             case CKR_SIGNATURE_INVALID:
 181                 return (gettext("signature invalid"));
 182             case CKR_SIGNATURE_LEN_RANGE:
 183                 return (gettext("signature len range"));
 184             case CKR_TEMPLATE_INCOMPLETE:
 185                 return (gettext("template incomplete"));
 186             case CKR_TEMPLATE_INCONSISTENT:
 187                 return (gettext("template inconsistent"));
 188             case CKR_TOKEN_NOT_PRESENT:
 189                 return (gettext("token not present"));
 190             case CKR_TOKEN_NOT_RECOGNIZED:
 191                 return (gettext("token not recognized"));
 192             case CKR_TOKEN_WRITE_PROTECTED:
 193                 return (gettext("token write protected"));
 194             case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
 195                 return (gettext("unwrapping key handle invalid"));
 196             case CKR_UNWRAPPING_KEY_SIZE_RANGE:
 197                 return (gettext("unwrapping key size range"));
 198             case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
 199                 return (gettext("unwrapping key type inconsistent"));
 200             case CKR_USER_ALREADY_LOGGED_IN:
 201                 return (gettext("user already logged in"));
 202             case CKR_USER_NOT_LOGGED_IN:
 203                 return (gettext("user not logged in"));
 204             case CKR_USER_PIN_NOT_INITIALIZED:
 205                 return (gettext("user pin not initialized"));
 206             case CKR_USER_TYPE_INVALID:
 207                 return (gettext("user type invalid"));
 208             case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
 209                 return (gettext("user another already logged in"));
 210             case CKR_USER_TOO_MANY_TYPES:
 211                 return (gettext("user too many types"));
 212             case CKR_WRAPPED_KEY_INVALID:
 213                 return (gettext("wrapped key invalid"));
 214             case CKR_WRAPPED_KEY_LEN_RANGE:
 215                 return (gettext("wrapped key len range"));
 216             case CKR_WRAPPING_KEY_HANDLE_INVALID:
 217                 return (gettext("wrapping key handle invalid"));
 218             case CKR_WRAPPING_KEY_SIZE_RANGE:
 219                 return (gettext("wrapping key size range"));
 220             case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
 221                 return (gettext("wrapping key type inconsistent"));
 222             case CKR_RANDOM_SEED_NOT_SUPPORTED:
 223                 return (gettext("random seed not supported"));
 224             case CKR_RANDOM_NO_RNG:
 225                 return (gettext("random no rng"));
 226             case CKR_DOMAIN_PARAMS_INVALID:
 227                 return (gettext("domain params invalid"));
 228             case CKR_BUFFER_TOO_SMALL:
 229                 return (gettext("buffer too small"));
 230             case CKR_SAVED_STATE_INVALID:
 231                 return (gettext("saved state invalid"));
 232             case CKR_INFORMATION_SENSITIVE:
 233                 return (gettext("information sensitive"));
 234             case CKR_STATE_UNSAVEABLE:
 235                 return (gettext("state unsaveable"));
 236             case CKR_CRYPTOKI_NOT_INITIALIZED:
 237                 return (gettext("cryptoki not initialized"));
 238             case CKR_CRYPTOKI_ALREADY_INITIALIZED:
 239                 return (gettext("cryptoki already initialized"));
 240             case CKR_MUTEX_BAD:
 241                 return (gettext("mutex bad"));
 242             case CKR_MUTEX_NOT_LOCKED:
 243                 return (gettext("mutex not locked"));
 244             case CKR_FUNCTION_REJECTED:
 245                 return (gettext("function rejected"));
 246             default:
 247                 return (gettext("unknown error"));
 248         }
 249 }
 250 
 251 /* DH parameters */
 252 unsigned char pkinit_1024_dhprime[128] = {
 253     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 254     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
 255     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 256     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
 257     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
 258     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 259     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
 260     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
 261     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 262     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
 263     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
 264     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 265     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
 266     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
 267     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
 268     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 269 };
 270 
 271 unsigned char pkinit_2048_dhprime[2048/8] = {
 272     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 273     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
 274     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 275     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
 276     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
 277     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 278     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
 279     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
 280     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 281     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
 282     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
 283     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 284     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
 285     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
 286     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
 287     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
 288     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
 289     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
 290     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
 291     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
 292     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
 293     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
 294     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
 295     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
 296     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
 297     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
 298     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
 299     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
 300     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
 301     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
 302     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
 303     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 304 };
 305 
 306 unsigned char pkinit_4096_dhprime[4096/8] = {
 307     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 308     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
 309     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 310     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
 311     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
 312     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 313     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
 314     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
 315     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 316     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
 317     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
 318     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 319     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
 320     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
 321     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
 322     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
 323     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
 324     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
 325     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
 326     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
 327     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
 328     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
 329     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
 330     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
 331     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
 332     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
 333     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
 334     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
 335     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
 336     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
 337     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
 338     0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
 339     0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
 340     0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
 341     0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
 342     0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
 343     0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
 344     0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
 345     0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
 346     0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
 347     0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
 348     0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
 349     0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
 350     0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
 351     0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
 352     0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
 353     0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
 354     0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
 355     0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
 356     0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
 357     0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
 358     0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
 359     0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
 360     0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
 361     0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
 362     0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
 363     0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
 364     0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
 365     0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
 366     0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
 367     0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
 368     0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
 369     0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
 370     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 371 };
 372 
 373 krb5_error_code
 374 pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) {
 375 
 376     krb5_error_code retval = ENOMEM;
 377     pkinit_plg_crypto_context ctx = NULL;
 378 
 379     /* initialize openssl routines */
 380     /* Solaris Kerberos */
 381     retval = openssl_init();
 382     if (retval != 0)
 383         goto out;
 384 
 385     ctx = (pkinit_plg_crypto_context)malloc(sizeof(*ctx));
 386     if (ctx == NULL)
 387         goto out;
 388     (void) memset(ctx, 0, sizeof(*ctx));
 389 
 390     pkiDebug("%s: initializing openssl crypto context at %p\n",
 391              __FUNCTION__, ctx);
 392     retval = pkinit_init_pkinit_oids(ctx);
 393     if (retval)
 394         goto out;
 395 
 396     retval = pkinit_init_dh_params(ctx);
 397     if (retval)
 398         goto out;
 399 
 400     *cryptoctx = ctx;
 401 
 402 out:
 403     if (retval && ctx != NULL)
 404             pkinit_fini_plg_crypto(ctx);
 405 
 406     return retval;
 407 }
 408 
 409 void
 410 pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)
 411 {
 412     pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx);
 413 
 414     if (cryptoctx == NULL)
 415         return;
 416     pkinit_fini_pkinit_oids(cryptoctx);
 417     pkinit_fini_dh_params(cryptoctx);
 418     free(cryptoctx);
 419 }
 420 
 421 krb5_error_code
 422 pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
 423 {
 424     krb5_error_code retval = ENOMEM;
 425     pkinit_identity_crypto_context ctx = NULL;
 426 
 427     ctx = (pkinit_identity_crypto_context)malloc(sizeof(*ctx));
 428     if (ctx == NULL)
 429         goto out;
 430     (void) memset(ctx, 0, sizeof(*ctx));
 431 
 432     retval = pkinit_init_certs(ctx);
 433     if (retval)
 434         goto out;
 435 
 436     retval = pkinit_init_pkcs11(ctx);
 437     if (retval)
 438         goto out;
 439 
 440     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
 441     *idctx = ctx;
 442 
 443 out:
 444     if (retval) {
 445         if (ctx)
 446             pkinit_fini_identity_crypto(ctx);
 447     }
 448 
 449     return retval;
 450 }
 451 
 452 void
 453 pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
 454 {
 455     if (idctx == NULL)
 456         return;
 457 
 458     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, idctx);
 459     pkinit_fini_certs(idctx);
 460     pkinit_fini_pkcs11(idctx);
 461     free(idctx);
 462 }
 463 
 464 krb5_error_code
 465 pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
 466 {
 467 
 468     pkinit_req_crypto_context ctx = NULL;
 469 
 470     /* Solaris Kerberos */
 471     if (cryptoctx == NULL)
 472         return EINVAL;
 473 
 474     ctx = (pkinit_req_crypto_context)malloc(sizeof(*ctx));
 475     if (ctx == NULL)
 476         return ENOMEM;
 477     (void) memset(ctx, 0, sizeof(*ctx));
 478 
 479     ctx->dh = NULL;
 480     ctx->received_cert = NULL;
 481 
 482     *cryptoctx = ctx;
 483 
 484     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
 485 
 486     return 0;
 487 }
 488 
 489 void
 490 pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
 491 {
 492     if (req_cryptoctx == NULL)
 493         return;
 494 
 495     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, req_cryptoctx);
 496     if (req_cryptoctx->dh != NULL)
 497       DH_free(req_cryptoctx->dh);
 498     if (req_cryptoctx->received_cert != NULL)
 499       X509_free(req_cryptoctx->received_cert);
 500 
 501     free(req_cryptoctx);
 502 }
 503 
 504 static krb5_error_code
 505 pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
 506 {
 507     ctx->id_pkinit_san = OBJ_txt2obj("1.3.6.1.5.2.2", 1);
 508     if (ctx->id_pkinit_san == NULL)
 509         return ENOMEM;
 510 
 511     ctx->id_pkinit_authData = OBJ_txt2obj("1.3.6.1.5.2.3.1", 1);
 512     if (ctx->id_pkinit_authData == NULL)
 513         return ENOMEM;
 514 
 515     ctx->id_pkinit_DHKeyData = OBJ_txt2obj("1.3.6.1.5.2.3.2", 1);
 516     if (ctx->id_pkinit_DHKeyData == NULL)
 517         return ENOMEM;
 518 
 519     ctx->id_pkinit_rkeyData = OBJ_txt2obj("1.3.6.1.5.2.3.3", 1);
 520     if (ctx->id_pkinit_rkeyData == NULL)
 521         return ENOMEM;
 522 
 523     ctx->id_pkinit_KPClientAuth = OBJ_txt2obj("1.3.6.1.5.2.3.4", 1);
 524     if (ctx->id_pkinit_KPClientAuth == NULL)
 525         return ENOMEM;
 526 
 527     ctx->id_pkinit_KPKdc = OBJ_txt2obj("1.3.6.1.5.2.3.5", 1);
 528     if (ctx->id_pkinit_KPKdc == NULL)
 529         return ENOMEM;
 530 
 531     ctx->id_ms_kp_sc_logon = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.2", 1);
 532     if (ctx->id_ms_kp_sc_logon == NULL)
 533         return ENOMEM;
 534 
 535     ctx->id_ms_san_upn = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.3", 1);
 536     if (ctx->id_ms_san_upn == NULL)
 537         return ENOMEM;
 538 
 539     ctx->id_kp_serverAuth = OBJ_txt2obj("1.3.6.1.5.5.7.3.1", 1);
 540     if (ctx->id_kp_serverAuth == NULL)
 541         return ENOMEM;
 542 
 543     return 0;
 544 }
 545 
 546 static krb5_error_code
 547 get_cert(char *filename, X509 **retcert)
 548 {
 549     X509 *cert = NULL;
 550     BIO *tmp = NULL;
 551     int code;
 552     krb5_error_code retval;
 553 
 554     if (filename == NULL || retcert == NULL)
 555         return EINVAL;
 556 
 557     *retcert = NULL;
 558 
 559     tmp = BIO_new(BIO_s_file());
 560     if (tmp == NULL)
 561         return ENOMEM;
 562 
 563     code = BIO_read_filename(tmp, filename);
 564     if (code == 0) {
 565         retval = errno;
 566         goto cleanup;
 567     }
 568 
 569     cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL);
 570     if (cert == NULL) {
 571         retval = EIO;
 572         pkiDebug("failed to read certificate from %s\n", filename);
 573         goto cleanup;
 574     }
 575     *retcert = cert;
 576     retval = 0;
 577 cleanup:
 578     if (tmp != NULL)
 579         BIO_free(tmp);
 580     return retval;
 581 }
 582 
 583 static krb5_error_code
 584 get_key(char *filename, EVP_PKEY **retkey)
 585 {
 586     EVP_PKEY *pkey = NULL;
 587     BIO *tmp = NULL;
 588     int code;
 589     krb5_error_code retval;
 590 
 591     if (filename == NULL || retkey == NULL)
 592         return EINVAL;
 593 
 594     tmp = BIO_new(BIO_s_file());
 595     if (tmp == NULL)
 596         return ENOMEM;
 597 
 598     code = BIO_read_filename(tmp, filename);
 599     if (code == 0) {
 600         retval = errno;
 601         goto cleanup;
 602     }
 603     pkey = (EVP_PKEY *) PEM_read_bio_PrivateKey(tmp, NULL, NULL, NULL);
 604     if (pkey == NULL) {
 605         retval = EIO;
 606         pkiDebug("failed to read private key from %s\n", filename);
 607         goto cleanup;
 608     }
 609     *retkey = pkey;
 610     retval = 0;
 611 cleanup:
 612     if (tmp != NULL)
 613         BIO_free(tmp);
 614     return retval;
 615 }
 616 
 617 static void
 618 pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
 619 {
 620     if (ctx == NULL)
 621         return;
 622     ASN1_OBJECT_free(ctx->id_pkinit_san);
 623     ASN1_OBJECT_free(ctx->id_pkinit_authData);
 624     ASN1_OBJECT_free(ctx->id_pkinit_DHKeyData);
 625     ASN1_OBJECT_free(ctx->id_pkinit_rkeyData);
 626     ASN1_OBJECT_free(ctx->id_pkinit_KPClientAuth);
 627     ASN1_OBJECT_free(ctx->id_pkinit_KPKdc);
 628     ASN1_OBJECT_free(ctx->id_ms_kp_sc_logon);
 629     ASN1_OBJECT_free(ctx->id_ms_san_upn);
 630     ASN1_OBJECT_free(ctx->id_kp_serverAuth);
 631 }
 632 
 633 static krb5_error_code
 634 pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
 635 {
 636     krb5_error_code retval = ENOMEM;
 637 
 638     plgctx->dh_1024 = DH_new();
 639     if (plgctx->dh_1024 == NULL)
 640         goto cleanup;
 641     plgctx->dh_1024->p = BN_bin2bn(pkinit_1024_dhprime,
 642         sizeof(pkinit_1024_dhprime), NULL);
 643     if ((plgctx->dh_1024->g = BN_new()) == NULL ||
 644         (plgctx->dh_1024->q = BN_new()) == NULL)
 645         goto cleanup;
 646     BN_set_word(plgctx->dh_1024->g, DH_GENERATOR_2);
 647     BN_rshift1(plgctx->dh_1024->q, plgctx->dh_1024->p);
 648 
 649     plgctx->dh_2048 = DH_new();
 650     if (plgctx->dh_2048 == NULL)
 651         goto cleanup;
 652     plgctx->dh_2048->p = BN_bin2bn(pkinit_2048_dhprime,
 653         sizeof(pkinit_2048_dhprime), NULL);
 654     if ((plgctx->dh_2048->g = BN_new()) == NULL ||
 655         (plgctx->dh_2048->q = BN_new()) == NULL)
 656         goto cleanup;
 657     BN_set_word(plgctx->dh_2048->g, DH_GENERATOR_2);
 658     BN_rshift1(plgctx->dh_2048->q, plgctx->dh_2048->p);
 659 
 660     plgctx->dh_4096 = DH_new();
 661     if (plgctx->dh_4096 == NULL)
 662         goto cleanup;
 663     plgctx->dh_4096->p = BN_bin2bn(pkinit_4096_dhprime,
 664         sizeof(pkinit_4096_dhprime), NULL);
 665     if ((plgctx->dh_4096->g = BN_new()) == NULL ||
 666         (plgctx->dh_4096->q = BN_new()) == NULL)
 667         goto cleanup;
 668     BN_set_word(plgctx->dh_4096->g, DH_GENERATOR_2);
 669     BN_rshift1(plgctx->dh_4096->q, plgctx->dh_4096->p);
 670 
 671     retval = 0;
 672 
 673 cleanup:
 674     if (retval)
 675         pkinit_fini_dh_params(plgctx);
 676 
 677     return retval;
 678 }
 679 
 680 static void
 681 pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
 682 {
 683     if (plgctx->dh_1024 != NULL)
 684         DH_free(plgctx->dh_1024);
 685     if (plgctx->dh_2048 != NULL)
 686         DH_free(plgctx->dh_2048);
 687     if (plgctx->dh_4096 != NULL)
 688         DH_free(plgctx->dh_4096);
 689 
 690     plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
 691 }
 692 
 693 static krb5_error_code
 694 pkinit_init_certs(pkinit_identity_crypto_context ctx)
 695 {
 696     /* Solaris Kerberos */
 697     int i;
 698 
 699     for (i = 0; i < MAX_CREDS_ALLOWED; i++)
 700         ctx->creds[i] = NULL;
 701     ctx->my_certs = NULL;
 702     ctx->cert_index = 0;
 703     ctx->my_key = NULL;
 704     ctx->trustedCAs = NULL;
 705     ctx->intermediateCAs = NULL;
 706     ctx->revoked = NULL;
 707 
 708     return 0;
 709 }
 710 
 711 static void
 712 pkinit_fini_certs(pkinit_identity_crypto_context ctx)
 713 {
 714     if (ctx == NULL)
 715         return;
 716 
 717     if (ctx->my_certs != NULL)
 718         sk_X509_pop_free(ctx->my_certs, X509_free);
 719 
 720     if (ctx->my_key != NULL)
 721         EVP_PKEY_free(ctx->my_key);
 722 
 723     if (ctx->trustedCAs != NULL)
 724         sk_X509_pop_free(ctx->trustedCAs, X509_free);
 725 
 726     if (ctx->intermediateCAs != NULL)
 727         sk_X509_pop_free(ctx->intermediateCAs, X509_free);
 728 
 729     if (ctx->revoked != NULL)
 730         sk_X509_CRL_pop_free(ctx->revoked, X509_CRL_free);
 731 }
 732 
 733 static krb5_error_code
 734 pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)
 735 {
 736     /* Solaris Kerberos */
 737 
 738 #ifndef WITHOUT_PKCS11
 739     ctx->p11_module_name = strdup(PKCS11_MODNAME);
 740     if (ctx->p11_module_name == NULL)
 741         return ENOMEM;
 742     ctx->p11_module = NULL;
 743     ctx->slotid = PK_NOSLOT;
 744     ctx->token_label = NULL;
 745     ctx->cert_label = NULL;
 746     ctx->PIN = NULL;
 747     ctx->session = CK_INVALID_HANDLE;
 748     ctx->p11 = NULL;
 749     ctx->p11flags = 0; /* Solaris Kerberos */
 750 #endif
 751     ctx->pkcs11_method = 0;
 752     (void) memset(ctx->creds, 0, sizeof(ctx->creds));
 753 
 754     return 0;
 755 }
 756 
 757 static void
 758 pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
 759 {
 760 #ifndef WITHOUT_PKCS11
 761     if (ctx == NULL)
 762         return;
 763 
 764     if (ctx->p11 != NULL) {
 765         if (ctx->session != CK_INVALID_HANDLE) {
 766             ctx->p11->C_CloseSession(ctx->session);
 767             ctx->session = CK_INVALID_HANDLE;
 768         }
 769         /*
 770          * Solaris Kerberos:
 771          * Only call C_Finalize if the process was not already using pkcs11.
 772          */
 773         if (ctx->finalize_pkcs11 == TRUE)
 774             ctx->p11->C_Finalize(NULL_PTR);
 775 
 776         ctx->p11 = NULL;
 777     }
 778     if (ctx->p11_module != NULL) {
 779         pkinit_C_UnloadModule(ctx->p11_module);
 780         ctx->p11_module = NULL;
 781     }
 782     if (ctx->p11_module_name != NULL)
 783         free(ctx->p11_module_name);
 784     if (ctx->token_label != NULL)
 785         free(ctx->token_label);
 786     if (ctx->cert_id != NULL)
 787         free(ctx->cert_id);
 788     if (ctx->cert_label != NULL)
 789         free(ctx->cert_label);
 790     if (ctx->PIN != NULL) {
 791         (void) memset(ctx->PIN, 0, strlen(ctx->PIN));
 792         free(ctx->PIN);
 793     }
 794 #endif
 795 }
 796 
 797 krb5_error_code
 798 pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
 799                              krb5_prompter_fct prompter,
 800                              void *prompter_data)
 801 {
 802     id_cryptoctx->prompter = prompter;
 803     id_cryptoctx->prompter_data = prompter_data;
 804 
 805     return 0;
 806 }
 807 
 808 /* ARGSUSED */
 809 krb5_error_code
 810 cms_signeddata_create(krb5_context context,
 811                       pkinit_plg_crypto_context plg_cryptoctx,
 812                       pkinit_req_crypto_context req_cryptoctx,
 813                       pkinit_identity_crypto_context id_cryptoctx,
 814                       int cms_msg_type,
 815                       int include_certchain,
 816                       unsigned char *data,
 817                       unsigned int data_len,
 818                       unsigned char **signed_data,
 819                       unsigned int *signed_data_len)
 820 {
 821     /* Solaris Kerberos */
 822     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
 823     PKCS7  *p7 = NULL, *inner_p7 = NULL;
 824     PKCS7_SIGNED *p7s = NULL;
 825     PKCS7_SIGNER_INFO *p7si = NULL;
 826     unsigned char *p;
 827     ASN1_TYPE *pkinit_data = NULL;
 828     STACK_OF(X509) * cert_stack = NULL;
 829     ASN1_OCTET_STRING *digest_attr = NULL;
 830     EVP_MD_CTX ctx, ctx2;
 831     const EVP_MD *md_tmp = NULL;
 832     unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
 833     unsigned char *digestInfo_buf = NULL, *abuf = NULL;
 834     unsigned int md_len, md_len2, alen, digestInfo_len;
 835     STACK_OF(X509_ATTRIBUTE) * sk;
 836     unsigned char *sig = NULL;
 837     unsigned int sig_len = 0;
 838     X509_ALGOR *alg = NULL;
 839     ASN1_OCTET_STRING *digest = NULL;
 840     unsigned int alg_len = 0, digest_len = 0;
 841     unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
 842     X509 *cert = NULL;
 843     ASN1_OBJECT *oid = NULL, *oid_copy;
 844 
 845     /* Solaris Kerberos */
 846     if (signed_data == NULL)
 847         return EINVAL;
 848 
 849     if (signed_data_len == NULL)
 850         return EINVAL;
 851 
 852     /* start creating PKCS7 data */
 853     if ((p7 = PKCS7_new()) == NULL)
 854         goto cleanup;
 855     p7->type = OBJ_nid2obj(NID_pkcs7_signed);
 856 
 857     if ((p7s = PKCS7_SIGNED_new()) == NULL)
 858         goto cleanup;
 859     p7->d.sign = p7s;
 860     if (!ASN1_INTEGER_set(p7s->version, 3))
 861         goto cleanup;
 862 
 863     /* create a cert chain that has at least the signer's certificate */
 864     if ((cert_stack = sk_X509_new_null()) == NULL)
 865         goto cleanup;
 866 
 867     cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
 868     if (!include_certchain) {
 869         pkiDebug("only including signer's certificate\n");
 870         sk_X509_push(cert_stack, X509_dup(cert));
 871     } else {
 872         /* create a cert chain */
 873         X509_STORE *certstore = NULL;
 874         X509_STORE_CTX certctx;
 875         STACK_OF(X509) *certstack = NULL;
 876         char buf[DN_BUF_LEN];
 877         int i = 0, size = 0;
 878 
 879         if ((certstore = X509_STORE_new()) == NULL)
 880             goto cleanup;
 881         pkiDebug("building certificate chain\n");
 882         X509_STORE_set_verify_cb_func(certstore, openssl_callback);
 883         X509_STORE_CTX_init(&certctx, certstore, cert,
 884                             id_cryptoctx->intermediateCAs);
 885         X509_STORE_CTX_trusted_stack(&certctx, id_cryptoctx->trustedCAs);
 886         /* Solaris Kerberos */
 887         if (X509_verify_cert(&certctx) <= 0) {
 888             pkiDebug("failed to create a certificate chain: %s\n", 
 889             X509_verify_cert_error_string(X509_STORE_CTX_get_error(&certctx)));
 890             if (!sk_X509_num(id_cryptoctx->trustedCAs)) 
 891                 pkiDebug("No trusted CAs found. Check your X509_anchors\n");
 892             goto cleanup;
 893         }
 894         certstack = X509_STORE_CTX_get1_chain(&certctx);
 895         size = sk_X509_num(certstack);
 896         pkiDebug("size of certificate chain = %d\n", size);
 897         for(i = 0; i < size - 1; i++) {
 898             X509 *x = sk_X509_value(certstack, i);
 899             X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
 900             pkiDebug("cert #%d: %s\n", i, buf);
 901             sk_X509_push(cert_stack, X509_dup(x));
 902         }
 903         X509_STORE_CTX_cleanup(&certctx);
 904         X509_STORE_free(certstore);
 905         sk_X509_pop_free(certstack, X509_free);
 906     }
 907     p7s->cert = cert_stack;
 908 
 909     /* fill-in PKCS7_SIGNER_INFO */
 910     if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
 911         goto cleanup;
 912     if (!ASN1_INTEGER_set(p7si->version, 1))
 913         goto cleanup;
 914     if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
 915                        X509_get_issuer_name(cert)))
 916         goto cleanup;
 917     /* because ASN1_INTEGER_set is used to set a 'long' we will do
 918      * things the ugly way. */
 919     M_ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
 920     if (!(p7si->issuer_and_serial->serial =
 921           M_ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
 922         goto cleanup;
 923 
 924     /* will not fill-out EVP_PKEY because it's on the smartcard */
 925 
 926     /* Set digest algs */
 927     p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
 928 
 929     if (p7si->digest_alg->parameter != NULL)
 930         ASN1_TYPE_free(p7si->digest_alg->parameter);
 931     if ((p7si->digest_alg->parameter = ASN1_TYPE_new()) == NULL)
 932         goto cleanup;
 933     p7si->digest_alg->parameter->type = V_ASN1_NULL;
 934 
 935     /* Set sig algs */
 936     if (p7si->digest_enc_alg->parameter != NULL)
 937         ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
 938     p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
 939     if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
 940         goto cleanup;
 941     p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
 942 
 943     /* pick the correct oid for the eContentInfo */
 944     oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
 945     if (oid == NULL)
 946         goto cleanup;
 947 
 948     if (cms_msg_type == CMS_SIGN_DRAFT9) {
 949         /* don't include signed attributes for pa-type 15 request */
 950         abuf = data;
 951         alen = data_len;
 952     } else {
 953         /* add signed attributes */
 954         /* compute sha1 digest over the EncapsulatedContentInfo */
 955         EVP_MD_CTX_init(&ctx);
 956         EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
 957         EVP_DigestUpdate(&ctx, data, data_len);
 958         md_tmp = EVP_MD_CTX_md(&ctx);
 959         EVP_DigestFinal_ex(&ctx, md_data, &md_len);
 960 
 961         /* create a message digest attr */
 962         digest_attr = ASN1_OCTET_STRING_new();
 963         ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
 964         PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
 965                                    V_ASN1_OCTET_STRING, (char *) digest_attr);
 966 
 967         /* create a content-type attr */
 968         oid_copy = OBJ_dup(oid);
 969         if (oid_copy == NULL)
 970                 goto cleanup2;
 971         PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType, 
 972                                    V_ASN1_OBJECT, oid_copy);
 973 
 974         /* create the signature over signed attributes. get DER encoded value */
 975         /* This is the place where smartcard signature needs to be calculated */
 976         sk = p7si->auth_attr;
 977         alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
 978                              ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
 979         if (abuf == NULL)
 980             goto cleanup2;
 981     }
 982 
 983 #ifndef WITHOUT_PKCS11
 984     /* Some tokens can only do RSAEncryption without sha1 hash */
 985     /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
 986      * function and the hash value into an ASN.1 value of type DigestInfo
 987      * DigestInfo::=SEQUENCE {
 988      *  digestAlgorithm  AlgorithmIdentifier,
 989      *  digest OCTET STRING }
 990      */
 991     if (id_cryptoctx->pkcs11_method == 1 && 
 992             id_cryptoctx->mech == CKM_RSA_PKCS) {
 993         pkiDebug("mech = CKM_RSA_PKCS\n");
 994         EVP_MD_CTX_init(&ctx2);
 995         /* if this is not draft9 request, include digest signed attribute */
 996         if (cms_msg_type != CMS_SIGN_DRAFT9) 
 997             EVP_DigestInit_ex(&ctx2, md_tmp, NULL);
 998         else
 999             EVP_DigestInit_ex(&ctx2, EVP_sha1(), NULL);
1000         EVP_DigestUpdate(&ctx2, abuf, alen);
1001         EVP_DigestFinal_ex(&ctx2, md_data2, &md_len2);
1002 
1003         alg = X509_ALGOR_new();
1004         if (alg == NULL)
1005             goto cleanup2;
1006         alg->algorithm = OBJ_nid2obj(NID_sha1);
1007         alg->parameter = NULL;
1008         alg_len = i2d_X509_ALGOR(alg, NULL);
1009         alg_buf = (unsigned char *)malloc(alg_len);
1010         if (alg_buf == NULL)
1011             goto cleanup2;
1012 
1013         digest = ASN1_OCTET_STRING_new();
1014         if (digest == NULL)
1015             goto cleanup2;
1016         ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
1017         digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
1018         digest_buf = (unsigned char *)malloc(digest_len);
1019         if (digest_buf == NULL)
1020             goto cleanup2;
1021 
1022         digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
1023                                           V_ASN1_SEQUENCE);
1024         y = digestInfo_buf = (unsigned char *)malloc(digestInfo_len);
1025         if (digestInfo_buf == NULL)
1026             goto cleanup2;
1027         ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
1028                         V_ASN1_UNIVERSAL);
1029         i2d_X509_ALGOR(alg, &y);
1030         i2d_ASN1_OCTET_STRING(digest, &y);
1031 #ifdef DEBUG_SIG
1032         pkiDebug("signing buffer\n");
1033         print_buffer(digestInfo_buf, digestInfo_len);
1034         print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
1035 #endif
1036         retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
1037                                   digestInfo_len, &sig, &sig_len);
1038     } else
1039 #endif
1040     {
1041         pkiDebug("mech = %s\n",
1042             id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
1043         retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
1044                                   &sig, &sig_len);
1045     }
1046 #ifdef DEBUG_SIG
1047     print_buffer(sig, sig_len);
1048 #endif
1049     if (cms_msg_type != CMS_SIGN_DRAFT9) 
1050         free(abuf);
1051     if (retval)
1052         goto cleanup2;
1053 
1054     /* Add signature */
1055     if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig,
1056                          (int)sig_len)) {
1057         unsigned long err = ERR_peek_error();
1058         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1059         krb5_set_error_message(context, retval, "%s\n",
1060                                ERR_error_string(err, NULL));
1061         pkiDebug("failed to add a signed digest attribute\n");
1062         goto cleanup2;
1063     }
1064     /* adder signer_info to pkcs7 signed */
1065     if (!PKCS7_add_signer(p7, p7si))
1066         goto cleanup2;
1067 
1068     /* start on adding data to the pkcs7 signed */
1069     if ((inner_p7 = PKCS7_new()) == NULL)
1070         goto cleanup2;
1071     if ((pkinit_data = ASN1_TYPE_new()) == NULL)
1072         goto cleanup2;
1073     pkinit_data->type = V_ASN1_OCTET_STRING;
1074     if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
1075         goto cleanup2;
1076     if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
1077                                (int)data_len)) {
1078         unsigned long err = ERR_peek_error();
1079         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1080         krb5_set_error_message(context, retval, "%s\n",
1081                                ERR_error_string(err, NULL));
1082         pkiDebug("failed to add pkcs7 data\n");
1083         goto cleanup2;
1084     }
1085 
1086     if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
1087         goto cleanup2;
1088 
1089     if (p7s->contents != NULL)
1090         PKCS7_free(p7s->contents);
1091     p7s->contents = inner_p7;
1092 
1093     *signed_data_len = i2d_PKCS7(p7, NULL);
1094     if (!(*signed_data_len)) {
1095         unsigned long err = ERR_peek_error();
1096         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1097         krb5_set_error_message(context, retval, "%s\n",
1098                                ERR_error_string(err, NULL));
1099         pkiDebug("failed to der encode pkcs7\n");
1100         goto cleanup2;
1101     }
1102     if ((p = *signed_data =
1103          (unsigned char *) malloc((size_t)*signed_data_len)) == NULL)
1104         goto cleanup2;
1105 
1106     /* DER encode PKCS7 data */
1107     retval = i2d_PKCS7(p7, &p);
1108     if (!retval) {
1109         unsigned long err = ERR_peek_error();
1110         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1111         krb5_set_error_message(context, retval, "%s\n",
1112                                ERR_error_string(err, NULL));
1113         pkiDebug("failed to der encode pkcs7\n");
1114         goto cleanup2;
1115     }
1116     retval = 0;
1117 
1118 #ifdef DEBUG_ASN1
1119     if (cms_msg_type == CMS_SIGN_CLIENT) {
1120         print_buffer_bin(*signed_data, *signed_data_len,
1121                          "/tmp/client_pkcs7_signeddata");
1122     } else {
1123         if (cms_msg_type == CMS_SIGN_SERVER) {
1124             print_buffer_bin(*signed_data, *signed_data_len,
1125                              "/tmp/kdc_pkcs7_signeddata");
1126         } else {
1127             print_buffer_bin(*signed_data, *signed_data_len,
1128                              "/tmp/draft9_pkcs7_signeddata");
1129         }
1130     }
1131 #endif
1132 
1133   cleanup2:
1134     if (cms_msg_type != CMS_SIGN_DRAFT9) 
1135         EVP_MD_CTX_cleanup(&ctx);
1136 #ifndef WITHOUT_PKCS11
1137     if (id_cryptoctx->pkcs11_method == 1 && 
1138             id_cryptoctx->mech == CKM_RSA_PKCS) {
1139         EVP_MD_CTX_cleanup(&ctx2);
1140         if (digest_buf != NULL)
1141             free(digest_buf);
1142         if (digestInfo_buf != NULL)
1143             free(digestInfo_buf);
1144         if (alg_buf != NULL)
1145             free(alg_buf);
1146         if (digest != NULL)
1147             ASN1_OCTET_STRING_free(digest);
1148     }
1149 #endif
1150     if (alg != NULL)
1151         X509_ALGOR_free(alg);
1152   cleanup:
1153     if (p7 != NULL) 
1154         PKCS7_free(p7);
1155     if (sig != NULL)
1156         free(sig);
1157 
1158     return retval;
1159 }
1160 
1161 krb5_error_code
1162 cms_signeddata_verify(krb5_context context,
1163                       pkinit_plg_crypto_context plgctx,
1164                       pkinit_req_crypto_context reqctx,
1165                       pkinit_identity_crypto_context idctx,
1166                       int cms_msg_type,
1167                       int require_crl_checking,
1168                       unsigned char *signed_data,
1169                       unsigned int signed_data_len,
1170                       unsigned char **data,
1171                       unsigned int *data_len,
1172                       unsigned char **authz_data,
1173                       unsigned int *authz_data_len)
1174 {
1175     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1176     PKCS7 *p7 = NULL;
1177     BIO *out = NULL;
1178     int flags = PKCS7_NOVERIFY, i = 0;
1179     unsigned int vflags = 0, size = 0;
1180     const unsigned char *p = signed_data;
1181     STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
1182     PKCS7_SIGNER_INFO *si = NULL;
1183     X509 *x = NULL;
1184     X509_STORE *store = NULL;
1185     X509_STORE_CTX cert_ctx;
1186     STACK_OF(X509) *intermediateCAs = NULL;
1187     STACK_OF(X509_CRL) *revoked = NULL;
1188     STACK_OF(X509) *verified_chain = NULL;
1189     ASN1_OBJECT *oid = NULL;
1190     krb5_external_principal_identifier **krb5_verified_chain = NULL;
1191     krb5_data *authz = NULL;
1192     char buf[DN_BUF_LEN];
1193 
1194 #ifdef DEBUG_ASN1
1195     print_buffer_bin(signed_data, signed_data_len,
1196                      "/tmp/client_received_pkcs7_signeddata");
1197 #endif
1198 
1199     /* Do this early enough to create the shadow OID for pkcs7-data if needed */
1200     oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
1201     if (oid == NULL)
1202         goto cleanup;
1203 
1204     /* decode received PKCS7 message */
1205     if ((p7 = d2i_PKCS7(NULL, &p, (int)signed_data_len)) == NULL) {
1206         unsigned long err = ERR_peek_error();
1207         krb5_set_error_message(context, retval, "%s\n",
1208                                ERR_error_string(err, NULL));
1209         pkiDebug("%s: failed to decode message: %s\n",
1210                  __FUNCTION__, ERR_error_string(err, NULL));
1211         goto cleanup;
1212     }
1213 
1214     /* verify that the received message is PKCS7 SignedData message */
1215     if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
1216         pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
1217                  OBJ_obj2nid(p7->type));
1218         krb5_set_error_message(context, retval, "wrong oid\n");
1219         goto cleanup;
1220     }
1221 
1222     /* setup to verify X509 certificate used to sign PKCS7 message */
1223     if (!(store = X509_STORE_new()))
1224         goto cleanup;
1225 
1226     /* check if we are inforcing CRL checking */
1227     vflags = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
1228     if (require_crl_checking)
1229         X509_STORE_set_verify_cb_func(store, openssl_callback);
1230     else
1231         X509_STORE_set_verify_cb_func(store, openssl_callback_ignore_crls);
1232     X509_STORE_set_flags(store, vflags);
1233 
1234     /* get the signer's information from the PKCS7 message */
1235     if ((si_sk = PKCS7_get_signer_info(p7)) == NULL)
1236         goto cleanup;
1237     if ((si = sk_PKCS7_SIGNER_INFO_value(si_sk, 0)) == NULL)
1238         goto cleanup;
1239     if ((x = PKCS7_cert_from_signer_info(p7, si)) == NULL)
1240         goto cleanup;
1241 
1242     /* create available CRL information (get local CRLs and include CRLs
1243      * received in the PKCS7 message
1244      */
1245     if (idctx->revoked == NULL)
1246         revoked = p7->d.sign->crl;
1247     else if (p7->d.sign->crl == NULL)
1248         revoked = idctx->revoked;
1249     else {
1250         size = sk_X509_CRL_num(idctx->revoked);
1251         revoked = sk_X509_CRL_new_null();
1252         for (i = 0; i < size; i++)
1253             sk_X509_CRL_push(revoked, sk_X509_CRL_value(idctx->revoked, i));
1254         size = sk_X509_CRL_num(p7->d.sign->crl);
1255         for (i = 0; i < size; i++)
1256             sk_X509_CRL_push(revoked, sk_X509_CRL_value(p7->d.sign->crl, i));
1257     }
1258 
1259     /* create available intermediate CAs chains (get local intermediateCAs and
1260      * include the CA chain received in the PKCS7 message
1261      */
1262     if (idctx->intermediateCAs == NULL)
1263         intermediateCAs = p7->d.sign->cert;
1264     else if (p7->d.sign->cert == NULL)
1265         intermediateCAs = idctx->intermediateCAs;
1266     else {
1267         size = sk_X509_num(idctx->intermediateCAs);
1268         intermediateCAs = sk_X509_new_null();
1269         for (i = 0; i < size; i++) {
1270             sk_X509_push(intermediateCAs,
1271                 sk_X509_value(idctx->intermediateCAs, i));
1272         }
1273         size = sk_X509_num(p7->d.sign->cert);
1274         for (i = 0; i < size; i++) {
1275             sk_X509_push(intermediateCAs, sk_X509_value(p7->d.sign->cert, i));
1276         }
1277     }
1278 
1279     /* initialize x509 context with the received certificate and
1280      * trusted and intermediate CA chains and CRLs
1281      */
1282     if (!X509_STORE_CTX_init(&cert_ctx, store, x, intermediateCAs))
1283         goto cleanup;
1284 
1285     X509_STORE_CTX_set0_crls(&cert_ctx, revoked);
1286 
1287     /* add trusted CAs certificates for cert verification */
1288     if (idctx->trustedCAs != NULL)
1289         X509_STORE_CTX_trusted_stack(&cert_ctx, idctx->trustedCAs);
1290     else {
1291         pkiDebug("unable to find any trusted CAs\n");
1292         goto cleanup;
1293     }
1294 #ifdef DEBUG_CERTCHAIN
1295     if (intermediateCAs != NULL) {
1296         size = sk_X509_num(intermediateCAs);
1297         pkiDebug("untrusted cert chain of size %d\n", size);
1298         for (i = 0; i < size; i++) {
1299             X509_NAME_oneline(X509_get_subject_name(
1300                 sk_X509_value(intermediateCAs, i)), buf, sizeof(buf));
1301             pkiDebug("cert #%d: %s\n", i, buf);
1302         }
1303     }
1304     if (idctx->trustedCAs != NULL) {
1305         size = sk_X509_num(idctx->trustedCAs);
1306         pkiDebug("trusted cert chain of size %d\n", size);
1307         for (i = 0; i < size; i++) {
1308             X509_NAME_oneline(X509_get_subject_name(
1309                 sk_X509_value(idctx->trustedCAs, i)), buf, sizeof(buf));
1310             pkiDebug("cert #%d: %s\n", i, buf);
1311         }
1312     }
1313     if (revoked != NULL) {
1314         size = sk_X509_CRL_num(revoked);
1315         pkiDebug("CRL chain of size %d\n", size);
1316         for (i = 0; i < size; i++) {
1317             X509_CRL *crl = sk_X509_CRL_value(revoked, i);
1318             X509_NAME_oneline(X509_CRL_get_issuer(crl), buf, sizeof(buf));
1319             pkiDebug("crls by CA #%d: %s\n", i , buf);
1320         }
1321     }
1322 #endif
1323 
1324     i = X509_verify_cert(&cert_ctx);
1325     if (i <= 0) {
1326         int j = X509_STORE_CTX_get_error(&cert_ctx);
1327 
1328         reqctx->received_cert = X509_dup(cert_ctx.current_cert);
1329         switch(j) {
1330             case X509_V_ERR_CERT_REVOKED:
1331                 retval = KRB5KDC_ERR_REVOKED_CERTIFICATE;
1332                 break;
1333             case X509_V_ERR_UNABLE_TO_GET_CRL:
1334                 retval = KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN;
1335                 break;
1336             case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
1337             case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
1338                 retval = KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE;
1339                 break;
1340             default:
1341                 retval = KRB5KDC_ERR_INVALID_CERTIFICATE;
1342         }
1343         X509_NAME_oneline(X509_get_subject_name(
1344             reqctx->received_cert), buf, sizeof(buf));
1345         pkiDebug("problem with cert DN = %s (error=%d) %s\n", buf, j,
1346                  X509_verify_cert_error_string(j));
1347         krb5_set_error_message(context, retval, "%s\n",
1348             X509_verify_cert_error_string(j));
1349 #ifdef DEBUG_CERTCHAIN
1350         size = sk_X509_num(p7->d.sign->cert);
1351         pkiDebug("received cert chain of size %d\n", size);
1352         for (j = 0; j < size; j++) {
1353             X509 *tmp_cert = sk_X509_value(p7->d.sign->cert, j);
1354             X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, sizeof(buf));
1355             pkiDebug("cert #%d: %s\n", j, buf);
1356         }
1357 #endif
1358     } else {
1359         /* retrieve verified certificate chain */
1360         if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9) 
1361             verified_chain = X509_STORE_CTX_get1_chain(&cert_ctx);
1362     }
1363     X509_STORE_CTX_cleanup(&cert_ctx);
1364     if (i <= 0)
1365         goto cleanup;
1366 
1367     out = BIO_new(BIO_s_mem());
1368     if (cms_msg_type == CMS_SIGN_DRAFT9)
1369         flags |= PKCS7_NOATTR;
1370     if (PKCS7_verify(p7, NULL, store, NULL, out, flags)) {
1371         int valid_oid = 0;
1372 
1373         if (!OBJ_cmp(p7->d.sign->contents->type, oid)) 
1374             valid_oid = 1;
1375         else if (cms_msg_type == CMS_SIGN_DRAFT9) {
1376             /*
1377              * Various implementations of the pa-type 15 request use
1378              * different OIDS.  We check that the returned object
1379              * has any of the acceptable OIDs
1380              */
1381             ASN1_OBJECT *client_oid = NULL, *server_oid = NULL, *rsa_oid = NULL;
1382             client_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_CLIENT);
1383             server_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_SERVER);
1384             rsa_oid = pkinit_pkcs7type2oid(plgctx, CMS_ENVEL_SERVER);
1385             if (!OBJ_cmp(p7->d.sign->contents->type, client_oid) ||
1386                 !OBJ_cmp(p7->d.sign->contents->type, server_oid) ||
1387                 !OBJ_cmp(p7->d.sign->contents->type, rsa_oid))
1388                 valid_oid = 1;
1389         }
1390 
1391         if (valid_oid) 
1392             pkiDebug("PKCS7 Verification successful\n");
1393         else {
1394             pkiDebug("wrong oid in eContentType\n");
1395             print_buffer((unsigned char *)p7->d.sign->contents->type->data, 
1396                 (unsigned int)p7->d.sign->contents->type->length);
1397             retval = KRB5KDC_ERR_PREAUTH_FAILED;
1398             krb5_set_error_message(context, retval, "wrong oid\n");
1399             goto cleanup;
1400         }
1401     }
1402     else {
1403         unsigned long err = ERR_peek_error();
1404         switch(ERR_GET_REASON(err)) {
1405             case PKCS7_R_DIGEST_FAILURE:
1406                 retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
1407                 break;
1408             case PKCS7_R_SIGNATURE_FAILURE:
1409             default:
1410                 retval = KRB5KDC_ERR_INVALID_SIG;
1411         }
1412         pkiDebug("PKCS7 Verification failure\n");
1413         krb5_set_error_message(context, retval, "%s\n",
1414                                ERR_error_string(err, NULL));
1415         goto cleanup;
1416     }
1417 
1418     /* transfer the data from PKCS7 message into return buffer */
1419     for (size = 0;;) {
1420         if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
1421             goto cleanup;
1422         i = BIO_read(out, &((*data)[size]), 1024 * 10);
1423         if (i <= 0)
1424             break;
1425         else
1426             size += i;
1427     }
1428     *data_len = size;
1429 
1430     reqctx->received_cert = X509_dup(x);
1431 
1432     /* generate authorization data */
1433     if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9) {
1434 
1435         if (authz_data == NULL || authz_data_len == NULL) 
1436             goto out;
1437 
1438         *authz_data = NULL;
1439         retval = create_identifiers_from_stack(verified_chain, 
1440                                                &krb5_verified_chain);
1441         if (retval) {
1442             pkiDebug("create_identifiers_from_stack failed\n");
1443             goto cleanup;
1444         }
1445 
1446         retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_verified_chain, &authz);
1447         if (retval) {
1448             pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
1449             goto cleanup;
1450         }
1451 #ifdef DEBUG_ASN1
1452         print_buffer_bin((unsigned char *)authz->data, authz->length,
1453                          "/tmp/kdc_ad_initial_verified_cas");
1454 #endif
1455         *authz_data = (unsigned char *)malloc(authz->length);
1456         if (*authz_data == NULL) {
1457             retval = ENOMEM;
1458             goto cleanup;
1459         }
1460         (void) memcpy(*authz_data, authz->data, authz->length);
1461         *authz_data_len = authz->length;
1462     }
1463   out:
1464     retval = 0;
1465 
1466   cleanup:
1467     if (out != NULL)
1468         BIO_free(out);
1469     if (store != NULL)
1470         X509_STORE_free(store);
1471     if (p7 != NULL) {
1472         if (idctx->intermediateCAs != NULL && p7->d.sign->cert)
1473             sk_X509_free(intermediateCAs);
1474         if (idctx->revoked != NULL && p7->d.sign->crl)
1475             sk_X509_CRL_free(revoked);
1476         PKCS7_free(p7);
1477     }
1478     if (verified_chain != NULL)
1479         sk_X509_pop_free(verified_chain, X509_free);
1480     if (krb5_verified_chain != NULL)
1481         free_krb5_external_principal_identifier(&krb5_verified_chain);
1482     if (authz != NULL)
1483         krb5_free_data(context, authz);
1484 
1485     return retval;
1486 }
1487 
1488 krb5_error_code
1489 cms_envelopeddata_create(krb5_context context,
1490                          pkinit_plg_crypto_context plgctx,
1491                          pkinit_req_crypto_context reqctx,
1492                          pkinit_identity_crypto_context idctx,
1493                          krb5_preauthtype pa_type,
1494                          int include_certchain,
1495                          unsigned char *key_pack,
1496                          unsigned int key_pack_len,
1497                          unsigned char **out,
1498                          unsigned int *out_len)
1499 {
1500 
1501     /* Solaris Kerberos */
1502     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
1503     PKCS7 *p7 = NULL;
1504     BIO *in = NULL;
1505     unsigned char *p = NULL, *signed_data = NULL, *enc_data = NULL;
1506     int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY;
1507     STACK_OF(X509) *encerts = NULL;
1508     const EVP_CIPHER *cipher = NULL;
1509     int cms_msg_type;
1510 
1511     /* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */
1512     switch ((int)pa_type) {
1513         case KRB5_PADATA_PK_AS_REQ_OLD:
1514         case KRB5_PADATA_PK_AS_REP_OLD:
1515             cms_msg_type = CMS_SIGN_DRAFT9;
1516             break;
1517         case KRB5_PADATA_PK_AS_REQ:
1518             cms_msg_type = CMS_ENVEL_SERVER;
1519             break;
1520         default:
1521             /* Solaris Kerberos */
1522             retval = EINVAL;
1523             goto cleanup;
1524     }
1525 
1526     retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
1527         cms_msg_type, include_certchain, key_pack, key_pack_len,
1528         &signed_data, (unsigned int *)&signed_data_len);
1529     if (retval) {
1530         pkiDebug("failed to create pkcs7 signed data\n");
1531         goto cleanup;
1532     }
1533 
1534     /* check we have client's certificate */
1535     if (reqctx->received_cert == NULL) {
1536         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1537         goto cleanup;
1538     }
1539     encerts = sk_X509_new_null();
1540     sk_X509_push(encerts, reqctx->received_cert);
1541 
1542     cipher = EVP_des_ede3_cbc();
1543     in = BIO_new(BIO_s_mem());
1544     switch (pa_type) {
1545         case KRB5_PADATA_PK_AS_REQ:
1546             prepare_enc_data(signed_data, signed_data_len, &enc_data,
1547                              &enc_data_len);
1548             retval = BIO_write(in, enc_data, enc_data_len);
1549             if (retval != enc_data_len) {
1550                 pkiDebug("BIO_write only wrote %d\n", retval);
1551                 goto cleanup;
1552             }
1553             break;
1554         case KRB5_PADATA_PK_AS_REP_OLD:
1555         case KRB5_PADATA_PK_AS_REQ_OLD:
1556             retval = BIO_write(in, signed_data, signed_data_len);
1557                 if (retval != signed_data_len) {
1558                     pkiDebug("BIO_write only wrote %d\n", retval);
1559                     /* Solaris Kerberos */
1560                     retval = KRB5KRB_ERR_GENERIC;
1561                     goto cleanup;
1562             }
1563             break;
1564         default:
1565             retval = -1;
1566             goto cleanup;
1567     }
1568 
1569     p7 = PKCS7_encrypt(encerts, in, cipher, flags);
1570     if (p7 == NULL) {
1571         pkiDebug("failed to encrypt PKCS7 object\n");
1572         retval = -1;
1573         goto cleanup;
1574     }
1575     switch (pa_type) {
1576         case KRB5_PADATA_PK_AS_REQ:
1577             p7->d.enveloped->enc_data->content_type = 
1578                 OBJ_nid2obj(NID_pkcs7_signed);
1579             break;
1580         case KRB5_PADATA_PK_AS_REP_OLD:
1581         case KRB5_PADATA_PK_AS_REQ_OLD:
1582             p7->d.enveloped->enc_data->content_type = 
1583                 OBJ_nid2obj(NID_pkcs7_data);
1584             break;
1585     } 
1586 
1587     *out_len = i2d_PKCS7(p7, NULL);
1588     if (!*out_len || (p = *out = (unsigned char *)malloc(*out_len)) == NULL) {
1589         retval = ENOMEM;
1590         goto cleanup;
1591     }
1592     retval = i2d_PKCS7(p7, &p);
1593     if (!retval) {
1594         pkiDebug("unable to write pkcs7 object\n");
1595         goto cleanup;
1596     }
1597     retval = 0;
1598 
1599 #ifdef DEBUG_ASN1
1600     print_buffer_bin(*out, *out_len, "/tmp/kdc_enveloped_data");
1601 #endif
1602 
1603 cleanup:
1604     if (p7 != NULL)
1605         PKCS7_free(p7);
1606     if (in != NULL)
1607         BIO_free(in);
1608     if (signed_data != NULL)
1609         free(signed_data);
1610     if (enc_data != NULL)
1611         free(enc_data);
1612     if (encerts != NULL)
1613         sk_X509_free(encerts);
1614         
1615     return retval;
1616 }
1617 
1618 krb5_error_code
1619 cms_envelopeddata_verify(krb5_context context,
1620                          pkinit_plg_crypto_context plg_cryptoctx,
1621                          pkinit_req_crypto_context req_cryptoctx,
1622                          pkinit_identity_crypto_context id_cryptoctx,
1623                          krb5_preauthtype pa_type,
1624                          int require_crl_checking,
1625                          unsigned char *enveloped_data,
1626                          unsigned int enveloped_data_len,
1627                          unsigned char **data,
1628                          unsigned int *data_len)
1629 {
1630     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1631     PKCS7 *p7 = NULL;
1632     BIO *out = NULL;
1633     int i = 0;
1634     unsigned int size = 0;
1635     const unsigned char *p = enveloped_data;
1636     unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0;
1637     unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL;
1638     int msg_type = 0;
1639 
1640 #ifdef DEBUG_ASN1
1641     print_buffer_bin(enveloped_data, enveloped_data_len,
1642                      "/tmp/client_envelopeddata");
1643 #endif
1644     /* decode received PKCS7 message */
1645     if ((p7 = d2i_PKCS7(NULL, &p, (int)enveloped_data_len)) == NULL) {
1646         unsigned long err = ERR_peek_error();
1647         pkiDebug("failed to decode pkcs7\n");
1648         krb5_set_error_message(context, retval, "%s\n",
1649                                ERR_error_string(err, NULL));
1650         goto cleanup;
1651     }
1652 
1653     /* verify that the received message is PKCS7 EnvelopedData message */
1654     if (OBJ_obj2nid(p7->type) != NID_pkcs7_enveloped) {
1655         pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n",
1656                  OBJ_obj2nid(p7->type));
1657         krb5_set_error_message(context, retval, "wrong oid\n");
1658         goto cleanup;
1659     }
1660 
1661     /* decrypt received PKCS7 message */
1662     out = BIO_new(BIO_s_mem());
1663     if (pkcs7_decrypt(context, id_cryptoctx, p7, out)) {
1664         pkiDebug("PKCS7 decryption successful\n");
1665     } else {
1666         unsigned long err = ERR_peek_error();
1667         if (err != 0)
1668             krb5_set_error_message(context, retval, "%s\n",
1669                                    ERR_error_string(err, NULL));
1670         pkiDebug("PKCS7 decryption failed\n");
1671         goto cleanup;
1672     }
1673 
1674     /* transfer the decoded PKCS7 SignedData message into a separate buffer */
1675     for (;;) {
1676         if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL)
1677             goto cleanup;
1678         i = BIO_read(out, &(tmp_buf[size]), 1024 * 10);
1679         if (i <= 0)
1680             break;
1681         else
1682             size += i;
1683     }
1684     tmp_buf_len = size;
1685 
1686 #ifdef DEBUG_ASN1
1687     print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack");
1688 #endif
1689     /* verify PKCS7 SignedData message */
1690     switch (pa_type) {
1691         case KRB5_PADATA_PK_AS_REP:
1692             msg_type = CMS_ENVEL_SERVER;
1693 
1694             break;
1695         case KRB5_PADATA_PK_AS_REP_OLD:
1696             msg_type = CMS_SIGN_DRAFT9;
1697             break;
1698         default:
1699             pkiDebug("%s: unrecognized pa_type = %d\n", __FUNCTION__, pa_type);
1700             retval = KRB5KDC_ERR_PREAUTH_FAILED;
1701             goto cleanup;
1702     }
1703     /*
1704      * If this is the RFC style, wrap the signed data to make
1705      * decoding easier in the verify routine.
1706      * For draft9-compatible, we don't do anything because it
1707      * is already wrapped.
1708      */
1709 #ifdef LONGHORN_BETA_COMPAT
1710     /*
1711      * The Longhorn server returns the expected RFC-style data, but
1712      * it is missing the sequence tag and length, so it requires
1713      * special processing when wrapping.
1714      * This will hopefully be fixed before the final release and
1715      * this can all be removed.
1716      */
1717     if (msg_type == CMS_ENVEL_SERVER || longhorn == 1) {
1718         retval = wrap_signeddata(tmp_buf, tmp_buf_len,
1719                                  &tmp_buf2, &tmp_buf2_len, longhorn);
1720         if (retval) {
1721             pkiDebug("failed to encode signeddata\n");
1722             goto cleanup;
1723         }
1724         vfy_buf = tmp_buf2;
1725         vfy_buf_len = tmp_buf2_len;
1726 
1727     } else {
1728         vfy_buf = tmp_buf;
1729         vfy_buf_len = tmp_buf_len;
1730     }
1731 #else
1732     if (msg_type == CMS_ENVEL_SERVER) {
1733         retval = wrap_signeddata(tmp_buf, tmp_buf_len,
1734                                  &tmp_buf2, &tmp_buf2_len);
1735         if (retval) {
1736             pkiDebug("failed to encode signeddata\n");
1737             goto cleanup;
1738         }
1739         vfy_buf = tmp_buf2;
1740         vfy_buf_len = tmp_buf2_len;
1741 
1742     } else {
1743         vfy_buf = tmp_buf;
1744         vfy_buf_len = tmp_buf_len;
1745     }
1746 #endif
1747 
1748 #ifdef DEBUG_ASN1
1749     print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2");
1750 #endif
1751 
1752     retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx,
1753                                    id_cryptoctx, msg_type,
1754                                    require_crl_checking,
1755                                    vfy_buf, vfy_buf_len,
1756                                    data, data_len, NULL, NULL);
1757 
1758     if (!retval)
1759         pkiDebug("PKCS7 Verification Success\n");
1760     else {      
1761         pkiDebug("PKCS7 Verification Failure\n");
1762         goto cleanup;
1763     }
1764 
1765     retval = 0;
1766 
1767   cleanup:
1768 
1769     if (p7 != NULL)
1770         PKCS7_free(p7);
1771     if (out != NULL)
1772         BIO_free(out);
1773     if (tmp_buf != NULL)
1774         free(tmp_buf);
1775     if (tmp_buf2 != NULL)
1776         free(tmp_buf2);
1777 
1778     return retval;
1779 }
1780 
1781 /* ARGSUSED */
1782 static krb5_error_code
1783 crypto_retrieve_X509_sans(krb5_context context,
1784                           pkinit_plg_crypto_context plgctx,
1785                           pkinit_req_crypto_context reqctx,
1786                           X509 *cert,
1787                           krb5_principal **princs_ret,
1788                           krb5_principal **upn_ret,
1789                           unsigned char ***dns_ret)
1790 {
1791     krb5_error_code retval = EINVAL;
1792     char buf[DN_BUF_LEN];
1793     int p = 0, u = 0, d = 0;
1794     krb5_principal *princs = NULL;
1795     krb5_principal *upns = NULL;
1796     unsigned char **dnss = NULL;
1797     int i, num_found = 0;
1798 
1799     if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
1800         pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
1801         return retval;
1802     }
1803 
1804     if (cert == NULL) {
1805         pkiDebug("%s: no certificate!\n", __FUNCTION__);
1806         return retval;
1807     }
1808 
1809     X509_NAME_oneline(X509_get_subject_name(cert),
1810                       buf, sizeof(buf));
1811     pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf);
1812 
1813     if ((i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) >= 0) {
1814         X509_EXTENSION *ext = NULL;
1815         GENERAL_NAMES *ialt = NULL;
1816         GENERAL_NAME *gen = NULL;
1817         int ret = 0;
1818         unsigned int num_sans = 0;
1819 
1820         if (!(ext = X509_get_ext(cert, i)) || !(ialt = X509V3_EXT_d2i(ext))) {
1821             pkiDebug("%s: found no subject alt name extensions\n",
1822                      __FUNCTION__);
1823             goto cleanup;
1824         }
1825         num_sans = sk_GENERAL_NAME_num(ialt);
1826 
1827         pkiDebug("%s: found %d subject alt name extension(s)\n",
1828                  __FUNCTION__, num_sans);
1829 
1830         /* OK, we're likely returning something. Allocate return values */
1831         if (princs_ret != NULL) {
1832             princs = calloc(num_sans + 1, sizeof(krb5_principal));
1833             if (princs == NULL) {
1834                 retval = ENOMEM;
1835                 goto cleanup;
1836             }
1837         }
1838         if (upn_ret != NULL) {
1839             upns = calloc(num_sans + 1, sizeof(krb5_principal));
1840             if (upns == NULL) {
1841                 retval = ENOMEM;
1842                 goto cleanup;
1843             }
1844         }
1845         if (dns_ret != NULL) {
1846             dnss = calloc(num_sans + 1, sizeof(*dnss));
1847             if (dnss == NULL) {
1848                 retval = ENOMEM;
1849                 goto cleanup;
1850             }
1851         }
1852 
1853         for (i = 0; i < num_sans; i++) {
1854             krb5_data name = { 0, 0, NULL };
1855 
1856             gen = sk_GENERAL_NAME_value(ialt, i);
1857             switch (gen->type) {
1858             case GEN_OTHERNAME:
1859                 name.length = gen->d.otherName->value->value.sequence->length;
1860                 name.data = (char *)gen->d.otherName->value->value.sequence->data;
1861                 if (princs != NULL
1862                     && OBJ_cmp(plgctx->id_pkinit_san,
1863                                gen->d.otherName->type_id) == 0) {
1864 #ifdef DEBUG_ASN1
1865                     print_buffer_bin((unsigned char *)name.data, name.length,
1866                                      "/tmp/pkinit_san");
1867 #endif
1868                     ret = k5int_decode_krb5_principal_name(&name, &princs[p]);
1869                     if (ret) {
1870                         pkiDebug("%s: failed decoding pkinit san value\n",
1871                                  __FUNCTION__);
1872                     } else {
1873                         p++;
1874                         num_found++;
1875                     }
1876                 } else if (upns != NULL
1877                            && OBJ_cmp(plgctx->id_ms_san_upn,
1878                                       gen->d.otherName->type_id) == 0) {
1879                     ret = krb5_parse_name(context, name.data, &upns[u]);
1880                     if (ret) {
1881                         pkiDebug("%s: failed parsing ms-upn san value\n",
1882                                  __FUNCTION__);
1883                     } else {
1884                         u++;
1885                         num_found++;
1886                     }
1887                 } else {
1888                     pkiDebug("%s: unrecognized othername oid in SAN\n",
1889                              __FUNCTION__);
1890                     continue;
1891                 }
1892 
1893                 break;
1894             case GEN_DNS:
1895                 if (dnss != NULL) {
1896                     pkiDebug("%s: found dns name = %s\n",
1897                              __FUNCTION__, gen->d.dNSName->data);
1898                     dnss[d] = (unsigned char *)
1899                                     strdup((char *)gen->d.dNSName->data); 
1900                     if (dnss[d] == NULL) {
1901                         pkiDebug("%s: failed to duplicate dns name\n",
1902                                  __FUNCTION__);
1903                     } else {
1904                         d++;
1905                         num_found++;
1906                     }
1907                 }
1908                 break;
1909             default:
1910                 pkiDebug("%s: SAN type = %d expecting %d\n",
1911                          __FUNCTION__, gen->type, GEN_OTHERNAME);
1912             }
1913         }
1914         sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
1915     }
1916 
1917     retval = 0;
1918     if (princs)
1919         *princs_ret = princs;
1920     if (upns)
1921         *upn_ret = upns;
1922     if (dnss)
1923         *dns_ret = dnss;
1924 
1925   cleanup:
1926     if (retval) {
1927         if (princs != NULL) {
1928             for (i = 0; princs[i] != NULL; i++)
1929                 krb5_free_principal(context, princs[i]);
1930             free(princs);
1931         }
1932         if (upns != NULL) {
1933             for (i = 0; upns[i] != NULL; i++)
1934                 krb5_free_principal(context, upns[i]);
1935             free(upns);
1936         }
1937         if (dnss != NULL) {
1938             for (i = 0; dnss[i] != NULL; i++)
1939                 free(dnss[i]);
1940             free(dnss);
1941         }
1942     }
1943     return retval;
1944 }
1945 
1946 /* ARGSUSED */
1947 krb5_error_code
1948 crypto_retrieve_cert_sans(krb5_context context,
1949                           pkinit_plg_crypto_context plgctx,
1950                           pkinit_req_crypto_context reqctx,
1951                           pkinit_identity_crypto_context idctx,
1952                           krb5_principal **princs_ret,
1953                           krb5_principal **upn_ret,
1954                           unsigned char ***dns_ret)
1955 {
1956     krb5_error_code retval = EINVAL;
1957 
1958     if (reqctx->received_cert == NULL) {
1959         pkiDebug("%s: No certificate!\n", __FUNCTION__);
1960         return retval;
1961     }
1962 
1963     return crypto_retrieve_X509_sans(context, plgctx, reqctx,
1964                                      reqctx->received_cert, princs_ret,
1965                                      upn_ret, dns_ret);
1966 }
1967 
1968 /* ARGSUSED */
1969 krb5_error_code
1970 crypto_check_cert_eku(krb5_context context,
1971                       pkinit_plg_crypto_context plgctx,
1972                       pkinit_req_crypto_context reqctx,
1973                       pkinit_identity_crypto_context idctx,
1974                       int checking_kdc_cert,
1975                       int allow_secondary_usage,
1976                       int *valid_eku)
1977 {
1978     char buf[DN_BUF_LEN];
1979     int found_eku = 0;
1980     krb5_error_code retval = EINVAL;
1981     int i;
1982 
1983     /* Solaris Kerberos */
1984     if (valid_eku == NULL)
1985         return retval;
1986 
1987     *valid_eku = 0;
1988     if (reqctx->received_cert == NULL)
1989         goto cleanup;
1990 
1991     X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
1992                       buf, sizeof(buf));
1993     pkiDebug("%s: looking for EKUs in cert = %s\n", __FUNCTION__, buf);
1994 
1995     if ((i = X509_get_ext_by_NID(reqctx->received_cert,
1996                                  NID_ext_key_usage, -1)) >= 0) {
1997         EXTENDED_KEY_USAGE *extusage;
1998 
1999         extusage = X509_get_ext_d2i(reqctx->received_cert, NID_ext_key_usage,
2000                                     NULL, NULL);
2001         if (extusage) {
2002             pkiDebug("%s: found eku info in the cert\n", __FUNCTION__);
2003             for (i = 0; found_eku == 0 && i < sk_ASN1_OBJECT_num(extusage); i++) {
2004                 ASN1_OBJECT *tmp_oid;
2005 
2006                 tmp_oid = sk_ASN1_OBJECT_value(extusage, i);
2007                 pkiDebug("%s: checking eku %d of %d, allow_secondary = %d\n",
2008                          __FUNCTION__, i+1, sk_ASN1_OBJECT_num(extusage),
2009                          allow_secondary_usage);
2010                 if (checking_kdc_cert) {
2011                     if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPKdc) == 0)
2012                          || (allow_secondary_usage
2013                          && OBJ_cmp(tmp_oid, plgctx->id_kp_serverAuth) == 0))
2014                         found_eku = 1;
2015                 } else {
2016                     if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPClientAuth) == 0)
2017                          || (allow_secondary_usage
2018                          && OBJ_cmp(tmp_oid, plgctx->id_ms_kp_sc_logon) == 0))
2019                         found_eku = 1;
2020                 }
2021             }
2022         }
2023         EXTENDED_KEY_USAGE_free(extusage);
2024 
2025         if (found_eku) {
2026             ASN1_BIT_STRING *usage = NULL;
2027             pkiDebug("%s: found acceptable EKU, checking for digitalSignature\n", __FUNCTION__);
2028 
2029             /* check that digitalSignature KeyUsage is present */
2030             if ((usage = X509_get_ext_d2i(reqctx->received_cert,
2031                                           NID_key_usage, NULL, NULL))) {
2032 
2033                 if (!ku_reject(reqctx->received_cert,
2034                                X509v3_KU_DIGITAL_SIGNATURE)) {
2035                     pkiDebug("%s: found digitalSignature KU\n",
2036                              __FUNCTION__);
2037                     *valid_eku = 1;
2038                 } else
2039                     pkiDebug("%s: didn't find digitalSignature KU\n",
2040                              __FUNCTION__);
2041             }
2042             ASN1_BIT_STRING_free(usage);
2043         }
2044     }
2045     retval = 0;
2046 cleanup:
2047     pkiDebug("%s: returning retval %d, valid_eku %d\n",
2048              __FUNCTION__, retval, *valid_eku);
2049     return retval;
2050 }
2051 
2052 krb5_error_code
2053 pkinit_octetstring2key(krb5_context context,
2054                        krb5_enctype etype,
2055                        unsigned char *key,
2056                        unsigned int dh_key_len,
2057                        krb5_keyblock * key_block)
2058 {
2059     krb5_error_code retval;
2060     unsigned char *buf = NULL;
2061     unsigned char md[SHA_DIGEST_LENGTH];
2062     unsigned char counter;
2063     size_t keybytes, keylength, offset;
2064     krb5_data random_data;
2065 
2066 
2067     if ((buf = (unsigned char *) malloc(dh_key_len)) == NULL) {
2068         retval = ENOMEM;
2069         goto cleanup;
2070     }
2071     (void) memset(buf, 0, dh_key_len);
2072 
2073     counter = 0;
2074     offset = 0;
2075     do {
2076         SHA_CTX c;
2077 
2078         SHA1_Init(&c);
2079         SHA1_Update(&c, &counter, 1);
2080         SHA1_Update(&c, key, dh_key_len);
2081         SHA1_Final(md, &c);
2082 
2083         if (dh_key_len - offset < sizeof(md))
2084             (void) memcpy(buf + offset, md, dh_key_len - offset);
2085         else
2086             (void) memcpy(buf + offset, md, sizeof(md));
2087 
2088         offset += sizeof(md);
2089         counter++;
2090     } while (offset < dh_key_len);
2091 
2092     /* Solaris Kerberos */
2093     key_block->magic = KV5M_KEYBLOCK;
2094     key_block->enctype = etype;
2095 
2096     retval = krb5_c_keylengths(context, etype, &keybytes, &keylength);
2097     if (retval)
2098         goto cleanup;
2099 
2100     key_block->length = keylength;
2101     key_block->contents = calloc(keylength, sizeof(unsigned char *));
2102     if (key_block->contents == NULL) {
2103         retval = ENOMEM;
2104         goto cleanup;
2105     }
2106 
2107     random_data.length = keybytes;
2108     random_data.data = (char *)buf;
2109 
2110     retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
2111 
2112   cleanup:
2113     if (buf != NULL)
2114         free(buf);
2115     if (retval && key_block->contents != NULL && key_block->length != 0) {
2116         (void) memset(key_block->contents, 0, key_block->length);
2117         key_block->length = 0;
2118     }
2119 
2120     return retval;
2121 }
2122 
2123 /* ARGSUSED */
2124 krb5_error_code
2125 client_create_dh(krb5_context context,
2126                  pkinit_plg_crypto_context plg_cryptoctx,
2127                  pkinit_req_crypto_context cryptoctx,
2128                  pkinit_identity_crypto_context id_cryptoctx,
2129                  int dh_size,
2130                  unsigned char **dh_params,
2131                  unsigned int *dh_params_len,
2132                  unsigned char **dh_pubkey,
2133                  unsigned int *dh_pubkey_len)
2134 {
2135     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2136     unsigned char *buf = NULL;
2137     int dh_err = 0;
2138     ASN1_INTEGER *pub_key = NULL;
2139 
2140     if (cryptoctx->dh == NULL) {
2141         if ((cryptoctx->dh = DH_new()) == NULL)
2142             goto cleanup;
2143         if ((cryptoctx->dh->g = BN_new()) == NULL ||
2144             (cryptoctx->dh->q = BN_new()) == NULL)
2145             goto cleanup;
2146 
2147         switch(dh_size) {
2148             case 1024:
2149                 pkiDebug("client uses 1024 DH keys\n");
2150                 cryptoctx->dh->p = get_rfc2409_prime_1024(NULL);
2151                 break;
2152             case 2048:
2153                 pkiDebug("client uses 2048 DH keys\n");
2154                 cryptoctx->dh->p = BN_bin2bn(pkinit_2048_dhprime,
2155                     sizeof(pkinit_2048_dhprime), NULL);
2156                 break;
2157             case 4096:
2158                 pkiDebug("client uses 4096 DH keys\n");
2159                 cryptoctx->dh->p = BN_bin2bn(pkinit_4096_dhprime,
2160                     sizeof(pkinit_4096_dhprime), NULL);
2161                 break;
2162             default:
2163                 goto cleanup;
2164         }
2165 
2166         BN_set_word((cryptoctx->dh->g), DH_GENERATOR_2);
2167         BN_rshift1(cryptoctx->dh->q, cryptoctx->dh->p);
2168     }
2169 
2170     DH_generate_key(cryptoctx->dh);
2171 /* Solaris Kerberos */
2172 #ifdef DEBUG
2173     DH_check(cryptoctx->dh, &dh_err);
2174     if (dh_err != 0) {
2175         pkiDebug("Warning: dh_check failed with %d\n", dh_err);
2176         if (dh_err & DH_CHECK_P_NOT_PRIME)
2177             pkiDebug("p value is not prime\n");
2178         if (dh_err & DH_CHECK_P_NOT_SAFE_PRIME)
2179             pkiDebug("p value is not a safe prime\n");
2180         if (dh_err & DH_UNABLE_TO_CHECK_GENERATOR)
2181             pkiDebug("unable to check the generator value\n");
2182         if (dh_err & DH_NOT_SUITABLE_GENERATOR)
2183             pkiDebug("the g value is not a generator\n");
2184     }
2185 #endif
2186 #ifdef DEBUG_DH
2187     print_dh(cryptoctx->dh, "client's DH params\n");
2188     print_pubkey(cryptoctx->dh->pub_key, "client's pub_key=");
2189 #endif
2190 
2191     DH_check_pub_key(cryptoctx->dh, cryptoctx->dh->pub_key, &dh_err);
2192     if (dh_err != 0) {
2193         pkiDebug("dh_check_pub_key failed with %d\n", dh_err);
2194         goto cleanup;
2195     }
2196 
2197     /* pack DHparams */
2198     /* aglo: usually we could just call i2d_DHparams to encode DH params
2199      * however, PKINIT requires RFC3279 encoding and openssl does pkcs#3.
2200      */
2201     retval = pkinit_encode_dh_params(cryptoctx->dh->p, cryptoctx->dh->g,
2202         cryptoctx->dh->q, dh_params, dh_params_len);
2203     if (retval)
2204         goto cleanup;
2205 
2206     /* pack DH public key */
2207     /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2208      * encoding shall be used as the contents (the value) of the
2209      * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2210      * data element
2211      */
2212     if ((pub_key = BN_to_ASN1_INTEGER(cryptoctx->dh->pub_key, NULL)) == NULL)
2213         goto cleanup;
2214     *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
2215     if ((buf = *dh_pubkey = (unsigned char *)
2216             malloc((size_t) *dh_pubkey_len)) == NULL) {
2217         retval  = ENOMEM;
2218         goto cleanup;
2219     }
2220     i2d_ASN1_INTEGER(pub_key, &buf);
2221 
2222     if (pub_key != NULL)
2223         ASN1_INTEGER_free(pub_key);
2224 
2225     retval = 0;
2226     return retval;
2227 
2228   cleanup:
2229     if (cryptoctx->dh != NULL)
2230         DH_free(cryptoctx->dh);
2231     cryptoctx->dh = NULL;
2232     if (*dh_params != NULL)
2233         free(*dh_params);
2234     *dh_params = NULL;
2235     if (*dh_pubkey != NULL)
2236         free(*dh_pubkey);
2237     *dh_pubkey = NULL;
2238     if (pub_key != NULL)
2239         ASN1_INTEGER_free(pub_key);
2240 
2241     return retval;
2242 }
2243 
2244 /* ARGSUSED */
2245 krb5_error_code
2246 client_process_dh(krb5_context context,
2247                   pkinit_plg_crypto_context plg_cryptoctx,
2248                   pkinit_req_crypto_context cryptoctx,
2249                   pkinit_identity_crypto_context id_cryptoctx,
2250                   unsigned char *subjectPublicKey_data,
2251                   unsigned int subjectPublicKey_length,
2252                   unsigned char **client_key,
2253                   unsigned int *client_key_len)
2254 {
2255     /* Solaris Kerberos */
2256     krb5_error_code retval = KRB5_PREAUTH_FAILED;
2257     BIGNUM *server_pub_key = NULL;
2258     ASN1_INTEGER *pub_key = NULL;
2259     const unsigned char *p = NULL;
2260     unsigned char *data = NULL;
2261     long data_len;
2262 
2263     /* decode subjectPublicKey (retrieve INTEGER from OCTET_STRING) */
2264 
2265     if (der_decode_data(subjectPublicKey_data, (long)subjectPublicKey_length,
2266                         &data, &data_len) != 0) {
2267         pkiDebug("failed to decode subjectPublicKey\n");
2268         /* Solaris Kerberos */
2269         retval = KRB5_PREAUTH_FAILED;
2270         goto cleanup;
2271     }
2272 
2273     *client_key_len = DH_size(cryptoctx->dh);
2274     if ((*client_key = (unsigned char *)
2275             malloc((size_t) *client_key_len)) == NULL) {
2276         retval = ENOMEM;
2277         goto cleanup;
2278     }
2279     p = data;
2280     if ((pub_key = d2i_ASN1_INTEGER(NULL, &p, data_len)) == NULL)
2281         goto cleanup;
2282     if ((server_pub_key = ASN1_INTEGER_to_BN(pub_key, NULL)) == NULL)
2283         goto cleanup;
2284 
2285     DH_compute_key(*client_key, server_pub_key, cryptoctx->dh);
2286 #ifdef DEBUG_DH
2287     print_pubkey(server_pub_key, "server's pub_key=");
2288     pkiDebug("client secret key (%d)= ", *client_key_len);
2289     print_buffer(*client_key, *client_key_len);
2290 #endif
2291 
2292     retval = 0;
2293     if (server_pub_key != NULL)
2294         BN_free(server_pub_key);
2295     if (pub_key != NULL)
2296         ASN1_INTEGER_free(pub_key);
2297     if (data != NULL)
2298         free (data);
2299 
2300     return retval;
2301 
2302   cleanup:
2303     if (*client_key != NULL)
2304         free(*client_key);
2305     *client_key = NULL;
2306     if (pub_key != NULL)
2307         ASN1_INTEGER_free(pub_key);
2308     if (data != NULL)
2309         free (data);
2310 
2311     return retval;
2312 }
2313 
2314 /* ARGSUSED */
2315 krb5_error_code
2316 server_check_dh(krb5_context context,
2317                 pkinit_plg_crypto_context cryptoctx,
2318                 pkinit_req_crypto_context req_cryptoctx,
2319                 pkinit_identity_crypto_context id_cryptoctx,
2320                 krb5_octet_data *dh_params,
2321                 int minbits)
2322 {
2323     DH *dh = NULL;
2324     unsigned char *tmp = NULL;
2325     int dh_prime_bits;
2326     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2327 
2328     tmp = dh_params->data;
2329     dh = DH_new();
2330     dh = pkinit_decode_dh_params(&dh, &tmp, dh_params->length);
2331     if (dh == NULL) {
2332         pkiDebug("failed to decode dhparams\n");
2333         goto cleanup;
2334     }
2335 
2336     /* KDC SHOULD check to see if the key parameters satisfy its policy */
2337     dh_prime_bits = BN_num_bits(dh->p);
2338     if (minbits && dh_prime_bits < minbits) {
2339         pkiDebug("client sent dh params with %d bits, we require %d\n",
2340                  dh_prime_bits, minbits);
2341         goto cleanup;
2342     }
2343 
2344     /* check dhparams is group 2 */
2345     if (pkinit_check_dh_params(cryptoctx->dh_1024->p,
2346                                dh->p, dh->g, dh->q) == 0) {
2347         retval = 0;
2348         goto cleanup;
2349     }
2350 
2351     /* check dhparams is group 14 */
2352     if (pkinit_check_dh_params(cryptoctx->dh_2048->p,
2353                                dh->p, dh->g, dh->q) == 0) {
2354         retval = 0;
2355         goto cleanup;
2356     }
2357 
2358     /* check dhparams is group 16 */
2359     if (pkinit_check_dh_params(cryptoctx->dh_4096->p,
2360                                dh->p, dh->g, dh->q) == 0) {
2361         retval = 0;
2362         goto cleanup;
2363     }
2364 
2365   cleanup:
2366     if (retval == 0)
2367         req_cryptoctx->dh = dh;
2368     else
2369         DH_free(dh);
2370 
2371     return retval;
2372 }
2373 
2374 /* kdc's dh function */
2375 /* ARGSUSED */
2376 krb5_error_code
2377 server_process_dh(krb5_context context,
2378                   pkinit_plg_crypto_context plg_cryptoctx,
2379                   pkinit_req_crypto_context cryptoctx,
2380                   pkinit_identity_crypto_context id_cryptoctx,
2381                   unsigned char *data,
2382                   unsigned int data_len,
2383                   unsigned char **dh_pubkey,
2384                   unsigned int *dh_pubkey_len,
2385                   unsigned char **server_key,
2386                   unsigned int *server_key_len)
2387 {
2388     /* Solaris Kerberos */
2389     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2390     DH *dh = NULL, *dh_server = NULL;
2391     unsigned char *p = NULL;
2392     ASN1_INTEGER *pub_key = NULL;
2393 
2394     /* get client's received DH parameters that we saved in server_check_dh */
2395     dh = cryptoctx->dh;
2396 
2397     dh_server = DH_new();
2398     if (dh_server == NULL)
2399         goto cleanup;
2400     dh_server->p = BN_dup(dh->p);
2401     dh_server->g = BN_dup(dh->g);
2402     dh_server->q = BN_dup(dh->q);
2403 
2404     /* decode client's public key */
2405     p = data;
2406     pub_key = d2i_ASN1_INTEGER(NULL, (const unsigned char **)&p, (int)data_len);
2407     if (pub_key == NULL)
2408         goto cleanup;
2409     dh->pub_key = ASN1_INTEGER_to_BN(pub_key, NULL);
2410     if (dh->pub_key == NULL)
2411         goto cleanup;
2412     ASN1_INTEGER_free(pub_key);
2413 
2414     if (!DH_generate_key(dh_server))
2415         goto cleanup;
2416 
2417     /* generate DH session key */
2418     *server_key_len = DH_size(dh_server);
2419     if ((*server_key = (unsigned char *) malloc((size_t)*server_key_len)) == NULL)
2420         goto cleanup;
2421     DH_compute_key(*server_key, dh->pub_key, dh_server);
2422 
2423 #ifdef DEBUG_DH
2424     print_dh(dh_server, "client&server's DH params\n");
2425     print_pubkey(dh->pub_key, "client's pub_key=");
2426     print_pubkey(dh_server->pub_key, "server's pub_key=");
2427     pkiDebug("server secret key=");
2428     print_buffer(*server_key, *server_key_len);
2429 #endif
2430 
2431     /* KDC reply */
2432     /* pack DH public key */
2433     /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2434      * encoding shall be used as the contents (the value) of the
2435      * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2436      * data element
2437      */
2438     if ((pub_key = BN_to_ASN1_INTEGER(dh_server->pub_key, NULL)) == NULL)
2439         goto cleanup;
2440     *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
2441     if ((p = *dh_pubkey = (unsigned char *) malloc((size_t)*dh_pubkey_len)) == NULL)
2442         goto cleanup;
2443     i2d_ASN1_INTEGER(pub_key, &p);
2444     if (pub_key != NULL)
2445         ASN1_INTEGER_free(pub_key);
2446 
2447     retval = 0;
2448 
2449     if (dh_server != NULL)
2450         DH_free(dh_server);
2451     return retval;
2452 
2453   cleanup:
2454     if (dh_server != NULL)
2455         DH_free(dh_server);
2456     if (*dh_pubkey != NULL)
2457         free(*dh_pubkey);
2458     if (*server_key != NULL)
2459         free(*server_key);
2460 
2461     return retval;
2462 }
2463 
2464 /*
2465  * Solaris Kerberos:
2466  * Add locking around did_init to make it MT-safe.
2467  */
2468 static krb5_error_code
2469 openssl_init()
2470 {
2471     krb5_error_code ret = 0;
2472     static int did_init = 0;
2473     static k5_mutex_t init_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
2474 
2475     ret = k5_mutex_lock(&init_mutex);
2476     if (ret == 0) {
2477         if (!did_init) {
2478             /* initialize openssl routines */
2479             CRYPTO_malloc_init();
2480             ERR_load_crypto_strings();
2481             OpenSSL_add_all_algorithms();
2482             did_init++;
2483         }
2484         k5_mutex_unlock(&init_mutex);
2485     }
2486     return (ret);
2487 }
2488 
2489 static krb5_error_code
2490 pkinit_encode_dh_params(BIGNUM *p, BIGNUM *g, BIGNUM *q,
2491                         unsigned char **buf, unsigned int *buf_len)
2492 {
2493     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2494     int bufsize = 0, r = 0;
2495     unsigned char *tmp = NULL;
2496     ASN1_INTEGER *ap = NULL, *ag = NULL, *aq = NULL;
2497 
2498     if ((ap = BN_to_ASN1_INTEGER(p, NULL)) == NULL)
2499         goto cleanup;
2500     if ((ag = BN_to_ASN1_INTEGER(g, NULL)) == NULL)
2501         goto cleanup;
2502     if ((aq = BN_to_ASN1_INTEGER(q, NULL)) == NULL)
2503         goto cleanup;
2504     bufsize = i2d_ASN1_INTEGER(ap, NULL);
2505     bufsize += i2d_ASN1_INTEGER(ag, NULL);
2506     bufsize += i2d_ASN1_INTEGER(aq, NULL);
2507 
2508     r = ASN1_object_size(1, bufsize, V_ASN1_SEQUENCE);
2509 
2510     tmp = *buf = (unsigned char *)malloc((size_t) r);
2511     if (tmp == NULL)
2512         goto cleanup;
2513 
2514     ASN1_put_object(&tmp, 1, bufsize, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2515 
2516     i2d_ASN1_INTEGER(ap, &tmp);
2517     i2d_ASN1_INTEGER(ag, &tmp);
2518     i2d_ASN1_INTEGER(aq, &tmp);
2519 
2520     *buf_len = r;
2521 
2522     retval = 0;
2523 
2524 cleanup:
2525     if (ap != NULL)
2526         ASN1_INTEGER_free(ap);
2527     if (ag != NULL)
2528         ASN1_INTEGER_free(ag);
2529     if (aq != NULL)
2530         ASN1_INTEGER_free(aq);
2531 
2532     return retval;
2533 }
2534 
2535 static DH *
2536 pkinit_decode_dh_params(DH ** a, unsigned char **pp, unsigned int len)
2537 {
2538     ASN1_INTEGER ai, *aip = NULL;
2539     long length = (long) len;
2540 
2541     M_ASN1_D2I_vars(a, DH *, DH_new);
2542 
2543     M_ASN1_D2I_Init();
2544     M_ASN1_D2I_start_sequence();
2545     aip = &ai;
2546     ai.data = NULL;
2547     ai.length = 0;
2548     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2549     if (aip == NULL)
2550         return NULL;
2551     else {
2552         (*a)->p = ASN1_INTEGER_to_BN(aip, NULL);
2553         if ((*a)->p == NULL)
2554             return NULL;
2555         if (ai.data != NULL) {
2556             OPENSSL_free(ai.data);
2557             ai.data = NULL;
2558             ai.length = 0;
2559         }
2560     }
2561     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2562     if (aip == NULL)
2563         return NULL;
2564     else {
2565         (*a)->g = ASN1_INTEGER_to_BN(aip, NULL);
2566         if ((*a)->g == NULL)
2567             return NULL;
2568         if (ai.data != NULL) {
2569             OPENSSL_free(ai.data);
2570             ai.data = NULL;
2571             ai.length = 0;
2572         }
2573 
2574     }
2575     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2576     if (aip == NULL)
2577         return NULL;
2578     else {
2579         (*a)->q = ASN1_INTEGER_to_BN(aip, NULL);
2580         if ((*a)->q == NULL)
2581             return NULL;
2582         if (ai.data != NULL) {
2583             OPENSSL_free(ai.data);
2584             ai.data = NULL;
2585             ai.length = 0;
2586         }
2587 
2588     }
2589     M_ASN1_D2I_end_sequence();
2590     M_ASN1_D2I_Finish(a, DH_free, 0);
2591 
2592 }
2593 
2594 static krb5_error_code
2595 pkinit_create_sequence_of_principal_identifiers(
2596     krb5_context context,
2597     pkinit_plg_crypto_context plg_cryptoctx,
2598     pkinit_req_crypto_context req_cryptoctx,
2599     pkinit_identity_crypto_context id_cryptoctx,
2600     int type,
2601     krb5_data **out_data)
2602 {
2603     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2604     krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
2605     krb5_data *td_certifiers = NULL, *data = NULL;
2606     krb5_typed_data **typed_data = NULL;
2607 
2608     switch(type) {
2609         case TD_TRUSTED_CERTIFIERS:
2610             retval = create_krb5_trustedCertifiers(context, plg_cryptoctx,
2611                 req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2612             if (retval) {
2613                 pkiDebug("create_krb5_trustedCertifiers failed\n");
2614                 goto cleanup;
2615             }
2616             break;
2617         case TD_INVALID_CERTIFICATES:
2618             retval = create_krb5_invalidCertificates(context, plg_cryptoctx,
2619                 req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2620             if (retval) {
2621                 pkiDebug("create_krb5_invalidCertificates failed\n");
2622                 goto cleanup;
2623             }
2624             break;
2625         default:
2626             retval = -1;
2627             goto cleanup;
2628     }
2629 
2630     retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_trusted_certifiers, &td_certifiers);
2631     if (retval) {
2632         pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
2633         goto cleanup;
2634     }
2635 #ifdef DEBUG_ASN1
2636     print_buffer_bin((unsigned char *)td_certifiers->data,
2637                      td_certifiers->length, "/tmp/kdc_td_certifiers");
2638 #endif
2639     typed_data = malloc (2 * sizeof(krb5_typed_data *));
2640     if (typed_data == NULL) {
2641         retval = ENOMEM;
2642         goto cleanup;
2643     }
2644     typed_data[1] = NULL;
2645     init_krb5_typed_data(&typed_data[0]);
2646     if (typed_data[0] == NULL) {
2647         retval = ENOMEM;
2648         goto cleanup;
2649     }
2650     typed_data[0]->type = type;
2651     typed_data[0]->length = td_certifiers->length;
2652     typed_data[0]->data = (unsigned char *)td_certifiers->data;
2653     retval = k5int_encode_krb5_typed_data((const krb5_typed_data **)typed_data,
2654                                           &data);
2655     if (retval) {
2656         pkiDebug("encode_krb5_typed_data failed\n");
2657         goto cleanup;
2658     }
2659 #ifdef DEBUG_ASN1
2660     print_buffer_bin((unsigned char *)data->data, data->length,
2661                      "/tmp/kdc_edata");
2662 #endif
2663     *out_data = (krb5_data *)malloc(sizeof(krb5_data));
2664     (*out_data)->length = data->length;
2665     (*out_data)->data = (char *)malloc(data->length);
2666     (void) memcpy((*out_data)->data, data->data, data->length);
2667 
2668     retval = 0;
2669 
2670 cleanup:
2671     if (krb5_trusted_certifiers != NULL)
2672         free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
2673 
2674     if (data != NULL) {
2675         if (data->data != NULL)
2676             free(data->data);
2677         free(data);
2678     }
2679 
2680     if (td_certifiers != NULL)
2681         free(td_certifiers);
2682 
2683     if (typed_data != NULL)
2684         free_krb5_typed_data(&typed_data);
2685 
2686     return retval;
2687 }
2688 
2689 krb5_error_code
2690 pkinit_create_td_trusted_certifiers(krb5_context context,
2691                                     pkinit_plg_crypto_context plg_cryptoctx,
2692                                     pkinit_req_crypto_context req_cryptoctx,
2693                                     pkinit_identity_crypto_context id_cryptoctx,
2694                                     krb5_data **out_data)
2695 {
2696     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2697 
2698     retval = pkinit_create_sequence_of_principal_identifiers(context,
2699         plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2700         TD_TRUSTED_CERTIFIERS, out_data);
2701 
2702     return retval;
2703 }
2704 
2705 krb5_error_code
2706 pkinit_create_td_invalid_certificate(
2707         krb5_context context,
2708         pkinit_plg_crypto_context plg_cryptoctx,
2709         pkinit_req_crypto_context req_cryptoctx,
2710         pkinit_identity_crypto_context id_cryptoctx,
2711         krb5_data **out_data)
2712 {
2713     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2714 
2715     retval = pkinit_create_sequence_of_principal_identifiers(context,
2716         plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2717         TD_INVALID_CERTIFICATES, out_data);
2718 
2719     return retval;
2720 }
2721 
2722 /* ARGSUSED */
2723 krb5_error_code
2724 pkinit_create_td_dh_parameters(krb5_context context,
2725                                pkinit_plg_crypto_context plg_cryptoctx,
2726                                pkinit_req_crypto_context req_cryptoctx,
2727                                pkinit_identity_crypto_context id_cryptoctx,
2728                                pkinit_plg_opts *opts,
2729                                krb5_data **out_data)
2730 {
2731     /* Solaris Kerberos */
2732     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2733     unsigned int buf1_len = 0, buf2_len = 0, buf3_len = 0, i = 0;
2734     unsigned char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
2735     krb5_typed_data **typed_data = NULL;
2736     krb5_data *data = NULL, *encoded_algId = NULL;
2737     krb5_algorithm_identifier **algId = NULL;
2738 
2739     /* Solaris Kerberos */
2740     if (opts->dh_min_bits > 4096) {
2741         retval = EINVAL;
2742         goto cleanup;
2743     }
2744 
2745     if (opts->dh_min_bits <= 1024) {
2746         retval = pkinit_encode_dh_params(plg_cryptoctx->dh_1024->p,
2747             plg_cryptoctx->dh_1024->g, plg_cryptoctx->dh_1024->q,
2748             &buf1, &buf1_len);
2749         if (retval)
2750             goto cleanup;
2751     }
2752     if (opts->dh_min_bits <= 2048) {
2753         retval = pkinit_encode_dh_params(plg_cryptoctx->dh_2048->p,
2754             plg_cryptoctx->dh_2048->g, plg_cryptoctx->dh_2048->q,
2755             &buf2, &buf2_len);
2756         if (retval)
2757             goto cleanup;
2758     }
2759     retval = pkinit_encode_dh_params(plg_cryptoctx->dh_4096->p,
2760         plg_cryptoctx->dh_4096->g, plg_cryptoctx->dh_4096->q,
2761         &buf3, &buf3_len);
2762     if (retval)
2763         goto cleanup;
2764 
2765     if (opts->dh_min_bits <= 1024) {
2766         algId = malloc(4 * sizeof(krb5_algorithm_identifier *));
2767         if (algId == NULL)
2768             goto cleanup;
2769         algId[3] = NULL;
2770         algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2771         if (algId[0] == NULL)
2772             goto cleanup;
2773         algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
2774         if (algId[0]->parameters.data == NULL)
2775             goto cleanup;
2776         (void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
2777         algId[0]->parameters.length = buf2_len;
2778         algId[0]->algorithm = dh_oid;
2779 
2780         algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2781         if (algId[1] == NULL)
2782             goto cleanup;
2783         algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
2784         if (algId[1]->parameters.data == NULL)
2785             goto cleanup;
2786         (void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
2787         algId[1]->parameters.length = buf3_len;
2788         algId[1]->algorithm = dh_oid;
2789 
2790         algId[2] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2791         if (algId[2] == NULL)
2792             goto cleanup;
2793         algId[2]->parameters.data = (unsigned char *)malloc(buf1_len);
2794         if (algId[2]->parameters.data == NULL)
2795             goto cleanup;
2796         (void) memcpy(algId[2]->parameters.data, buf1, buf1_len);
2797         algId[2]->parameters.length = buf1_len;
2798         algId[2]->algorithm = dh_oid;
2799 
2800     } else if (opts->dh_min_bits <= 2048) {
2801         algId = malloc(3 * sizeof(krb5_algorithm_identifier *));
2802         if (algId == NULL)
2803             goto cleanup;
2804         algId[2] = NULL;
2805         algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2806         if (algId[0] == NULL)
2807             goto cleanup;
2808         algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
2809         if (algId[0]->parameters.data == NULL)
2810             goto cleanup;
2811         (void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
2812         algId[0]->parameters.length = buf2_len;
2813         algId[0]->algorithm = dh_oid;
2814 
2815         algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2816         if (algId[1] == NULL)
2817             goto cleanup;
2818         algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
2819         if (algId[1]->parameters.data == NULL)
2820             goto cleanup;
2821         (void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
2822         algId[1]->parameters.length = buf3_len;
2823         algId[1]->algorithm = dh_oid;
2824 
2825     } else if (opts->dh_min_bits <= 4096) {
2826         algId = malloc(2 * sizeof(krb5_algorithm_identifier *));
2827         if (algId == NULL)
2828             goto cleanup;
2829         algId[1] = NULL;
2830         algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2831         if (algId[0] == NULL)
2832             goto cleanup;
2833         algId[0]->parameters.data = (unsigned char *)malloc(buf3_len);
2834         if (algId[0]->parameters.data == NULL)
2835             goto cleanup;
2836         (void) memcpy(algId[0]->parameters.data, buf3, buf3_len);
2837         algId[0]->parameters.length = buf3_len;
2838         algId[0]->algorithm = dh_oid;
2839 
2840     }
2841     retval = k5int_encode_krb5_td_dh_parameters((const krb5_algorithm_identifier **)algId, &encoded_algId);
2842     if (retval)
2843         goto cleanup;
2844 #ifdef DEBUG_ASN1
2845     print_buffer_bin((unsigned char *)encoded_algId->data,
2846                      encoded_algId->length, "/tmp/kdc_td_dh_params");
2847 #endif
2848     typed_data = malloc (2 * sizeof(krb5_typed_data *));
2849     if (typed_data == NULL) {
2850         retval = ENOMEM;
2851         goto cleanup;
2852     }
2853     typed_data[1] = NULL;
2854     init_krb5_typed_data(&typed_data[0]);
2855     if (typed_data == NULL) {
2856         retval = ENOMEM;
2857         goto cleanup;
2858     }
2859     typed_data[0]->type = TD_DH_PARAMETERS;
2860     typed_data[0]->length = encoded_algId->length;
2861     typed_data[0]->data = (unsigned char *)encoded_algId->data;
2862     retval = k5int_encode_krb5_typed_data((const krb5_typed_data**)typed_data,
2863                                           &data);
2864     if (retval) {
2865         pkiDebug("encode_krb5_typed_data failed\n");
2866         goto cleanup;
2867     }
2868 #ifdef DEBUG_ASN1
2869     print_buffer_bin((unsigned char *)data->data, data->length,
2870                      "/tmp/kdc_edata");
2871 #endif
2872     *out_data = (krb5_data *)malloc(sizeof(krb5_data));
2873     if (*out_data == NULL)
2874         goto cleanup;
2875     (*out_data)->length = data->length;
2876     (*out_data)->data = (char *)malloc(data->length);
2877     if ((*out_data)->data == NULL) {
2878         free(*out_data);
2879         *out_data = NULL;
2880         goto cleanup;
2881     }
2882     (void) memcpy((*out_data)->data, data->data, data->length);
2883 
2884     retval = 0;
2885 cleanup:
2886 
2887     if (buf1 != NULL)
2888         free(buf1);
2889     if (buf2 != NULL)
2890         free(buf2);
2891     if (buf3 != NULL)
2892         free(buf3);
2893     if (data != NULL) {
2894         if (data->data != NULL)
2895             free(data->data);
2896         free(data);
2897     }
2898     if (typed_data != NULL)
2899         free_krb5_typed_data(&typed_data);
2900     if (encoded_algId != NULL)
2901         free(encoded_algId);
2902 
2903     if (algId != NULL) {
2904         while(algId[i] != NULL) {
2905             if (algId[i]->parameters.data != NULL)
2906                 free(algId[i]->parameters.data);
2907             free(algId[i]);
2908             i++;
2909         }
2910         free(algId);
2911     }
2912 
2913     return retval;
2914 }
2915 
2916 /* ARGSUSED */
2917 krb5_error_code
2918 pkinit_check_kdc_pkid(krb5_context context,
2919                       pkinit_plg_crypto_context plg_cryptoctx,
2920                       pkinit_req_crypto_context req_cryptoctx,
2921                       pkinit_identity_crypto_context id_cryptoctx,
2922                       unsigned char *pdid_buf,
2923                       unsigned int pkid_len,
2924                       int *valid_kdcPkId)
2925 {
2926     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2927     PKCS7_ISSUER_AND_SERIAL *is = NULL;
2928     const unsigned char *p = pdid_buf;
2929     int status = 1;
2930     X509 *kdc_cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
2931 
2932     *valid_kdcPkId = 0;
2933     pkiDebug("found kdcPkId in AS REQ\n");
2934     is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p, (int)pkid_len);
2935     if (is == NULL)
2936         goto cleanup;
2937 
2938     status = X509_NAME_cmp(X509_get_issuer_name(kdc_cert), is->issuer);
2939     if (!status) {
2940         status = ASN1_INTEGER_cmp(X509_get_serialNumber(kdc_cert), is->serial);
2941         if (!status)
2942             *valid_kdcPkId = 1;
2943     }
2944 
2945     retval = 0;
2946 cleanup:
2947     X509_NAME_free(is->issuer);
2948     ASN1_INTEGER_free(is->serial);
2949     free(is);
2950 
2951     return retval;
2952 }
2953 
2954 static int
2955 pkinit_check_dh_params(BIGNUM * p1, BIGNUM * p2, BIGNUM * g1, BIGNUM * q1)
2956 {
2957     BIGNUM *g2 = NULL, *q2 = NULL;
2958     /* Solaris Kerberos */
2959     int retval = EINVAL;
2960 
2961     if (!BN_cmp(p1, p2)) {
2962         g2 = BN_new();
2963         BN_set_word(g2, DH_GENERATOR_2);
2964         if (!BN_cmp(g1, g2)) {
2965             q2 = BN_new();
2966             BN_rshift1(q2, p1);
2967             if (!BN_cmp(q1, q2)) {
2968                 pkiDebug("good %d dhparams\n", BN_num_bits(p1));
2969                 retval = 0;
2970             } else
2971                 pkiDebug("bad group 2 q dhparameter\n");
2972             BN_free(q2);
2973         } else
2974             pkiDebug("bad g dhparameter\n");
2975         BN_free(g2);
2976     } else
2977         pkiDebug("p is not well-known group 2 dhparameter\n");
2978 
2979     return retval;
2980 }
2981 
2982 /* ARGSUSED */
2983 krb5_error_code
2984 pkinit_process_td_dh_params(krb5_context context,
2985                             pkinit_plg_crypto_context cryptoctx,
2986                             pkinit_req_crypto_context req_cryptoctx,
2987                             pkinit_identity_crypto_context id_cryptoctx,
2988                             krb5_algorithm_identifier **algId,
2989                             int *new_dh_size)
2990 {
2991     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2992     int i = 0, use_sent_dh = 0, ok = 0;
2993 
2994     pkiDebug("dh parameters\n");
2995 
2996     while (algId[i] != NULL) {
2997         DH *dh = NULL;
2998         unsigned char *tmp = NULL;
2999         int dh_prime_bits = 0;
3000 
3001         if (algId[i]->algorithm.length != dh_oid.length ||
3002             memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
3003             goto cleanup;
3004 
3005         tmp = algId[i]->parameters.data;
3006         dh = DH_new();
3007         dh = pkinit_decode_dh_params(&dh, &tmp, algId[i]->parameters.length);
3008         dh_prime_bits = BN_num_bits(dh->p);
3009         pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
3010                  *new_dh_size, dh_prime_bits);
3011         switch(dh_prime_bits) {
3012             case 1024:
3013                 if (pkinit_check_dh_params(cryptoctx->dh_1024->p, dh->p,
3014                         dh->g, dh->q) == 0) {
3015                     *new_dh_size = 1024;
3016                     ok = 1;
3017                 }
3018                 break;
3019             case 2048:
3020                 if (pkinit_check_dh_params(cryptoctx->dh_2048->p, dh->p,
3021                         dh->g, dh->q) == 0) {
3022                     *new_dh_size = 2048;
3023                     ok = 1;
3024                 }
3025                 break;
3026             case 4096:
3027                 if (pkinit_check_dh_params(cryptoctx->dh_4096->p, dh->p,
3028                         dh->g, dh->q) == 0) {
3029                     *new_dh_size = 4096;
3030                     ok = 1;
3031                 }
3032                 break;
3033             default:
3034                 break;
3035         }
3036         if (!ok) {
3037             DH_check(dh, &retval);
3038             if (retval != 0) {
3039                 pkiDebug("DH parameters provided by server are unacceptable\n");
3040                 retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
3041             }
3042             else {
3043                 use_sent_dh = 1;
3044                 ok = 1;
3045             }
3046         }
3047         if (!use_sent_dh)
3048             DH_free(dh);
3049         if (ok) {
3050             if (req_cryptoctx->dh != NULL) {
3051                 DH_free(req_cryptoctx->dh);
3052                 req_cryptoctx->dh = NULL;
3053             }
3054             if (use_sent_dh)
3055                 req_cryptoctx->dh = dh;
3056             break;
3057         }
3058         i++;
3059     }
3060 
3061     if (ok)
3062         retval = 0;
3063 
3064 cleanup:
3065     return retval;
3066 }
3067 
3068 /* ARGSUSED */ 
3069 static int
3070 openssl_callback(int ok, X509_STORE_CTX * ctx)
3071 {
3072 #ifdef DEBUG
3073     if (!ok) {
3074         char buf[DN_BUF_LEN];
3075 
3076         X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf));
3077         pkiDebug("cert = %s\n", buf);
3078         pkiDebug("callback function: %d (%s)\n", ctx->error,
3079                 X509_verify_cert_error_string(ctx->error));
3080     }
3081 #endif
3082     return ok;
3083 }
3084 
3085 static int
3086 openssl_callback_ignore_crls(int ok, X509_STORE_CTX * ctx)
3087 {
3088     if (!ok) {
3089         switch (ctx->error) {
3090             case X509_V_ERR_UNABLE_TO_GET_CRL:
3091                 return 1;
3092             default:
3093                 return 0;
3094         }
3095     }
3096     return ok;
3097 }
3098 
3099 static ASN1_OBJECT *
3100 pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
3101 {
3102     switch (pkcs7_type) {
3103         case CMS_SIGN_CLIENT:
3104             return cryptoctx->id_pkinit_authData;
3105         case CMS_SIGN_DRAFT9:
3106             return OBJ_nid2obj(NID_pkcs7_data);
3107         case CMS_SIGN_SERVER:
3108             return cryptoctx->id_pkinit_DHKeyData;
3109         case CMS_ENVEL_SERVER:
3110             return cryptoctx->id_pkinit_rkeyData;
3111         default:
3112             return NULL;
3113     }
3114 
3115 }
3116 
3117 #ifdef LONGHORN_BETA_COMPAT
3118 #if 0
3119 /*
3120  * This is a version that worked with Longhorn Beta 3.
3121  */
3122 static int
3123 wrap_signeddata(unsigned char *data, unsigned int data_len,
3124                 unsigned char **out, unsigned int *out_len,
3125                 int is_longhorn_server)
3126 {
3127 
3128     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3129     ASN1_OBJECT *oid = NULL;
3130     unsigned char *p = NULL;
3131 
3132     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3133              __FUNCTION__, is_longhorn_server);
3134 
3135     /* Get length to wrap the original data with SEQUENCE tag */
3136     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3137 
3138     if (is_longhorn_server == 0) {
3139         /* Add the signedData OID and adjust lengths */
3140         oid = OBJ_nid2obj(NID_pkcs7_signed);
3141         oid_len = i2d_ASN1_OBJECT(oid, NULL);
3142 
3143         tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3144     }
3145 
3146     p = *out = (unsigned char *)malloc(tot_len);
3147     if (p == NULL) return -1;
3148 
3149     if (is_longhorn_server == 0) {
3150         ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3151                         V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3152 
3153         i2d_ASN1_OBJECT(oid, &p);
3154 
3155         ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3156     } else {
3157         ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3158     }
3159     memcpy(p, data, data_len);
3160 
3161     *out_len = tot_len;
3162 
3163     return 0;
3164 }
3165 #else
3166 /*
3167  * This is a version that works with a patched Longhorn KDC.
3168  * (Which should match SP1 ??).
3169  */
3170 static int
3171 wrap_signeddata(unsigned char *data, unsigned int data_len,
3172                unsigned char **out, unsigned int *out_len,
3173                int is_longhorn_server)
3174 {
3175 
3176     unsigned int oid_len = 0, tot_len = 0, wrap_len = 0, tag_len = 0;
3177     ASN1_OBJECT *oid = NULL;
3178     unsigned char *p = NULL;
3179 
3180     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3181              __FUNCTION__, is_longhorn_server);
3182 
3183     /* New longhorn is missing another sequence */
3184     if (is_longhorn_server == 1)
3185        wrap_len = ASN1_object_size(1, (int)(data_len), V_ASN1_SEQUENCE);
3186     else
3187        wrap_len = data_len;
3188 
3189     /* Get length to wrap the original data with SEQUENCE tag */
3190     tag_len = ASN1_object_size(1, (int)wrap_len, V_ASN1_SEQUENCE);
3191 
3192     /* Always add oid */
3193     oid = OBJ_nid2obj(NID_pkcs7_signed);
3194     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3195     oid_len += tag_len;
3196 
3197     tot_len = ASN1_object_size(1, (int)(oid_len), V_ASN1_SEQUENCE);
3198 
3199     p = *out = (unsigned char *)malloc(tot_len);
3200     if (p == NULL)
3201        return -1;
3202 
3203     ASN1_put_object(&p, 1, (int)(oid_len),
3204                     V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3205 
3206     i2d_ASN1_OBJECT(oid, &p);
3207 
3208     ASN1_put_object(&p, 1, (int)wrap_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3209 
3210     /* Wrap in extra seq tag */
3211     if (is_longhorn_server == 1) {
3212        ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3213     }
3214     (void) memcpy(p, data, data_len);
3215 
3216     *out_len = tot_len;
3217 
3218     return 0;
3219 }
3220 
3221 #endif
3222 #else
3223 static int
3224 wrap_signeddata(unsigned char *data, unsigned int data_len,
3225                 unsigned char **out, unsigned int *out_len)
3226 {
3227 
3228     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3229     ASN1_OBJECT *oid = NULL;
3230     unsigned char *p = NULL;
3231 
3232     /* Get length to wrap the original data with SEQUENCE tag */
3233     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3234 
3235     /* Add the signedData OID and adjust lengths */
3236     oid = OBJ_nid2obj(NID_pkcs7_signed);
3237     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3238 
3239     tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3240 
3241     p = *out = (unsigned char *)malloc(tot_len);
3242     if (p == NULL) return -1;
3243 
3244     ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3245                     V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3246 
3247     i2d_ASN1_OBJECT(oid, &p);
3248 
3249     ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3250     (void) memcpy(p, data, data_len);
3251 
3252     *out_len = tot_len;
3253 
3254     return 0;
3255 }
3256 #endif
3257 
3258 static int
3259 prepare_enc_data(unsigned char *indata,
3260                  int indata_len,
3261                  unsigned char **outdata,
3262                  int *outdata_len)
3263 {
3264     /* Solaris Kerberos */
3265     ASN1_const_CTX c;
3266     long length = indata_len;
3267     int Ttag, Tclass;
3268     long Tlen;
3269 
3270     c.pp = (const unsigned char **)&indata;
3271     c.q = *(const unsigned char **)&indata;
3272     c.error = ERR_R_NESTED_ASN1_ERROR;
3273     c.p= *(const unsigned char **)&indata;
3274     c.max = (length == 0)?0:(c.p+length);
3275 
3276     asn1_GetSequence(&c,&length);
3277 
3278     ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
3279     c.p += Tlen;
3280     ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
3281 
3282     asn1_const_Finish(&c);
3283 
3284     *outdata = (unsigned char *)malloc((size_t)Tlen);
3285     /* Solaris Kerberos */
3286     if (outdata == NULL)
3287         return ENOMEM;
3288     
3289     (void) memcpy(*outdata, c.p, (size_t)Tlen);
3290     *outdata_len = Tlen;
3291 
3292     return 0;
3293 }
3294 
3295 #ifndef WITHOUT_PKCS11
3296 static void *
3297 pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
3298 {
3299     void *handle;
3300     CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
3301 
3302     pkiDebug("loading module \"%s\"... ", modname);
3303     /* Solaris Kerberos */
3304     handle = dlopen(modname, RTLD_NOW | RTLD_GROUP);
3305     if (handle == NULL) {
3306         pkiDebug("not found\n");
3307         return NULL;
3308     }
3309     getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
3310     if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
3311         (void) dlclose(handle);
3312         pkiDebug("failed\n");
3313         return NULL;
3314     }
3315     pkiDebug("ok\n");
3316     return handle;
3317 }
3318 
3319 static CK_RV
3320 pkinit_C_UnloadModule(void *handle)
3321 {
3322     /* Solaris Kerberos */
3323     if (dlclose(handle) != 0)
3324         return CKR_GENERAL_ERROR;
3325 
3326     return CKR_OK;
3327 }
3328 
3329 /*
3330  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3331  * code.
3332  *
3333  * labelstr will be C string containing token label with trailing white space
3334  * removed.
3335  */
3336 static void
3337 trim_token_label(CK_TOKEN_INFO *tinfo, char *labelstr, unsigned int labelstr_len)
3338 {
3339     int i;
3340 
3341     assert(labelstr_len > sizeof (tinfo->label));
3342     /*
3343      * \0 terminate labelstr in case the last char in the token label is
3344      * non-whitespace
3345      */
3346     labelstr[sizeof (tinfo->label)] = '\0';
3347     (void) memcpy(labelstr, (char *) tinfo->label, sizeof (tinfo->label));
3348 
3349     /* init i so terminating \0 is skipped */
3350     for (i = sizeof (tinfo->label) - 1; i >= 0; i--) {
3351         if (labelstr[i] == ' ')
3352             labelstr[i] = '\0';
3353         else
3354             break;
3355     }
3356 }
3357 
3358 /*
3359  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3360  * code.
3361  */
3362 static krb5_error_code
3363 pkinit_prompt_user(krb5_context context,
3364                    pkinit_identity_crypto_context cctx,
3365                    krb5_data *reply,
3366                    char *prompt,
3367                    int hidden)
3368 {
3369     krb5_error_code r;
3370     krb5_prompt kprompt;
3371     krb5_prompt_type prompt_type;
3372 
3373     if (cctx->prompter == NULL)
3374         return (EINVAL);
3375 
3376     kprompt.prompt = prompt;
3377     kprompt.hidden = hidden;
3378     kprompt.reply = reply;
3379     /*
3380      * Note, assuming this type for now, may need to be passed in in the future.
3381      */
3382     prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
3383 
3384     /* PROMPTER_INVOCATION */
3385     k5int_set_prompt_types(context, &prompt_type);
3386     r = (*cctx->prompter)(context, cctx->prompter_data,
3387                           NULL, NULL, 1, &kprompt);
3388     k5int_set_prompt_types(context, NULL);
3389     return (r);
3390 }
3391 
3392 /*
3393  * Solaris Kerberos: this function was changed to support a PIN being passed
3394  * in.  If that is the case the user will not be prompted for their PIN.
3395  */
3396 static krb5_error_code
3397 pkinit_login(krb5_context context,
3398              pkinit_identity_crypto_context id_cryptoctx,
3399              CK_TOKEN_INFO *tip)
3400 {
3401     krb5_data rdat;
3402     char *prompt;
3403     int prompt_len;
3404     int r = 0;
3405 
3406     if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
3407         rdat.data = NULL;
3408         rdat.length = 0;
3409     } else if (id_cryptoctx->PIN != NULL) {
3410         if ((rdat.data = strdup(id_cryptoctx->PIN)) == NULL)
3411             return (ENOMEM);
3412         /*
3413          * Don't include NULL string terminator in length calculation as this
3414          * PIN is passed to the C_Login function and only the text chars should
3415          * be considered to be the PIN.
3416          */
3417         rdat.length = strlen(id_cryptoctx->PIN);
3418     } else {
3419         /* Solaris Kerberos - trim token label */
3420         char tmplabel[sizeof (tip->label) + 1];
3421 
3422         if (!id_cryptoctx->prompter) {
3423             pkiDebug("pkinit_login: id_cryptoctx->prompter is NULL\n");
3424             /* Solaris Kerberos: Improved error messages */
3425             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3426                 gettext("Failed to log into token: prompter function is NULL"));
3427             return (KRB5KDC_ERR_PREAUTH_FAILED);
3428         }
3429         /* Solaris Kerberos - Changes for gettext() */
3430         prompt_len = sizeof (tip->label) + 256;
3431         if ((prompt = (char *) malloc(prompt_len)) == NULL)
3432             return ENOMEM;
3433 
3434         /* Solaris Kerberos - trim token label which can be padded with space */
3435         trim_token_label(tip, tmplabel, sizeof (tmplabel));
3436         (void) snprintf(prompt, prompt_len, gettext("%s PIN"), tmplabel);
3437 
3438         /* Solaris Kerberos */
3439         if (tip->flags & CKF_USER_PIN_LOCKED)
3440             (void) strlcat(prompt, gettext(" (Warning: PIN locked)"), prompt_len);
3441         else if (tip->flags & CKF_USER_PIN_FINAL_TRY)
3442             (void) strlcat(prompt, gettext(" (Warning: PIN final try)"), prompt_len);
3443         else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
3444             (void) strlcat(prompt, gettext(" (Warning: PIN count low)"), prompt_len);
3445         rdat.data = malloc(tip->ulMaxPinLen + 2);
3446         rdat.length = tip->ulMaxPinLen + 1;
3447         /*
3448          * Note that the prompter function will set rdat.length such that the
3449          * NULL terminator is not included
3450          */
3451         /* PROMPTER_INVOCATION */
3452         r = pkinit_prompt_user(context, id_cryptoctx, &rdat, prompt, 1);
3453         free(prompt);
3454     }
3455 
3456     if (r == 0) {
3457         r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
3458                 (u_char *) rdat.data, rdat.length);
3459 
3460         if (r != CKR_OK) {
3461             pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r));
3462             /* Solaris Kerberos: Improved error messages */
3463             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3464                 gettext("Failed to log into token: %s"),
3465                 pkinit_pkcs11_code_to_text(r));
3466             r = KRB5KDC_ERR_PREAUTH_FAILED;
3467         } else {
3468             /* Solaris Kerberos: only need to login once */
3469             id_cryptoctx->p11flags |= C_LOGIN_DONE;
3470         }
3471     }
3472     if (rdat.data) {
3473         (void) memset(rdat.data, 0, rdat.length);
3474         free(rdat.data);
3475     }
3476 
3477     return (r);
3478 }
3479 
3480 /*
3481  * Solaris Kerberos: added these structs in support of prompting user for
3482  * missing token.
3483  */
3484 struct _token_entry {
3485     CK_SLOT_ID slotID;
3486     CK_SESSION_HANDLE session;
3487     CK_TOKEN_INFO token_info;
3488 };
3489 struct _token_choices {
3490     unsigned int numtokens;
3491     struct _token_entry *token_array;
3492 };
3493 
3494 
3495 /*
3496  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3497  * code.
3498  */
3499 static krb5_error_code
3500 pkinit_prompt_token(krb5_context context,
3501                     pkinit_identity_crypto_context cctx)
3502 {
3503     char tmpbuf[4];
3504     krb5_data reply;
3505     char *token_prompt = gettext("If you have a smartcard insert it now. "
3506                                  "Press enter to continue");
3507 
3508     reply.data = tmpbuf;
3509     reply.length = sizeof(tmpbuf);
3510 
3511     /* note, don't care about the reply */
3512     return (pkinit_prompt_user(context, cctx, &reply, token_prompt, 0));
3513 }
3514 
3515 /*
3516  * Solaris Kerberos: new defines for prompting support.
3517  */
3518 #define CHOOSE_THIS_TOKEN 0
3519 #define CHOOSE_RESCAN 1
3520 #define CHOOSE_SKIP 2
3521 #define CHOOSE_SEE_NEXT 3
3522 
3523 #define RESCAN_TOKENS -1
3524 #define SKIP_TOKENS -2
3525 
3526 /*
3527  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3528  * code.
3529  *
3530  * This prompts to user for various choices regarding a token to use.  Note
3531  * that if there is no error, choice will be set to one of:
3532  * - the token_choices->token_array entry
3533  * - RESCAN_TOKENS
3534  * - SKIP_TOKENS
3535  */
3536 static int
3537 pkinit_choose_tokens(krb5_context context,
3538                      pkinit_identity_crypto_context cctx,
3539                      struct _token_choices *token_choices,
3540                      int *choice)
3541 {
3542     krb5_error_code r;
3543     /*
3544      * Assuming that PAM_MAX_MSG_SIZE is a reasonable restriction. Note that -
3545      * 2 is to account for the fact that a krb prompter to PAM conv bridge will
3546      * add ": ".
3547      */
3548     char prompt[PAM_MAX_MSG_SIZE - 2];
3549     char tmpbuf[4];
3550     char tmplabel[sizeof (token_choices->token_array->token_info.label) + 1];
3551     krb5_data reply;
3552     int i, num_used, tmpchoice;
3553 
3554     assert(token_choices != NULL);
3555     assert(choice != NULL);
3556 
3557     /* Create the menu prompt */
3558 
3559     /* only need to do this once before the for loop */
3560     reply.data = tmpbuf;
3561 
3562     for (i = 0; i < token_choices->numtokens; i++) {
3563 
3564         trim_token_label(&token_choices->token_array[i].token_info, tmplabel,
3565                          sizeof (tmplabel));
3566 
3567         if (i == (token_choices->numtokens - 1)) {
3568             /* no more smartcards/tokens */
3569             if ((num_used = snprintf(prompt, sizeof (prompt),
3570                                      "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n",
3571                                      /*
3572                                       * TRANSLATION_NOTE: Translations of the
3573                                       * following 5 strings must not exceed 450
3574                                       * bytes total.
3575                                       */
3576                                      gettext("Select one of the following and press enter:"),
3577                                      CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3578                                      gettext("in slot"), token_choices->token_array[i].slotID,
3579                                      CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3580                                      CHOOSE_SKIP, gettext("Skip smartcard authentication")))
3581                 >= sizeof (prompt)) {
3582                 pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3583                          " sizeof prompt: %d\n", num_used, sizeof (prompt));
3584                 krb5_set_error_message(context, EINVAL,
3585                                gettext("In pkinit_choose_tokens: prompt size"
3586                                       " %d exceeds prompt buffer size %d"),
3587                                num_used, sizeof(prompt));
3588                 (void) snprintf(prompt, sizeof (prompt), "%s",
3589                                 gettext("Error: PKINIT prompt message is too large for buffer, "
3590                                         "please alert the system administrator. Press enter to "
3591                                         "continue"));
3592                 reply.length = sizeof(tmpbuf);
3593                 if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3594                     return (r);
3595                 return (EINVAL);
3596             }
3597         } else {
3598             if ((num_used = snprintf(prompt, sizeof (prompt),
3599                                      "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n%d: %s\n",
3600                                      /*
3601                                       * TRANSLATION_NOTE: Translations of the
3602                                       * following 6 strings must not exceed 445
3603                                       * bytes total.
3604                                       */
3605                                      gettext("Select one of the following and press enter:"),
3606                                      CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3607                                      gettext("in slot"), token_choices->token_array[i].slotID,
3608                                      CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3609                                      CHOOSE_SKIP, gettext("Skip smartcard authentication"),
3610                                      CHOOSE_SEE_NEXT, gettext("See next smartcard")))
3611                 >= sizeof (prompt)) {
3612 
3613                 pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3614                          " sizeof prompt: %d\n", num_used, sizeof (prompt));
3615                 krb5_set_error_message(context, EINVAL,
3616                                        gettext("In pkinit_choose_tokens: prompt size"
3617                                                " %d exceeds prompt buffer size %d"),
3618                                        num_used, sizeof(prompt));
3619                 (void) snprintf(prompt, sizeof (prompt), "%s",
3620                                 gettext("Error: PKINIT prompt message is too large for buffer, "
3621                                         "please alert the system administrator. Press enter to "
3622                                         "continue"));
3623                 reply.length = sizeof(tmpbuf);
3624                 if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3625                     return (r);
3626                 return (EINVAL);
3627             }
3628         }
3629 
3630         /*
3631          * reply.length needs to be reset to length of tmpbuf before calling
3632          * prompter
3633          */
3634         reply.length = sizeof(tmpbuf);
3635         if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3636             return (r);
3637 
3638         if (reply.length == 0) {
3639             return (EINVAL);
3640         } else {
3641             char *cp = reply.data;
3642             /* reply better be digits */
3643             while (*cp != NULL) {
3644                 if (!isdigit(*cp++))
3645                     return (EINVAL);
3646             }
3647             errno = 0;
3648             tmpchoice = (int) strtol(reply.data, (char **)NULL, 10);
3649             if (errno != 0)
3650                 return (errno);
3651         }
3652 
3653         switch (tmpchoice) {
3654         case CHOOSE_THIS_TOKEN:
3655             *choice = i; /* chosen entry of token_choices->token_array */
3656             return (0);
3657         case CHOOSE_RESCAN:
3658             *choice = RESCAN_TOKENS; /* rescan for new smartcard */
3659             return (0);
3660         case CHOOSE_SKIP:
3661             *choice = SKIP_TOKENS; /* skip smartcard auth */
3662             return (0);
3663         case CHOOSE_SEE_NEXT: /* see next smartcard */
3664             continue;
3665         default:
3666             return (EINVAL);
3667         }
3668     }
3669 
3670     return (0);
3671 }
3672 
3673 /*
3674  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3675  * code.
3676  *
3677  * Note, this isn't the best solution to providing a function to check the
3678  * certs in a token however I wanted to avoid rewriting a bunch of code so I
3679  * settled for some duplication of processing.
3680  */
3681 static krb5_error_code
3682 check_load_certs(krb5_context context,
3683             CK_SESSION_HANDLE session,
3684             pkinit_plg_crypto_context plg_cryptoctx,
3685             pkinit_req_crypto_context req_cryptoctx,
3686             pkinit_identity_crypto_context id_cryptoctx,
3687             krb5_principal princ,
3688             int do_matching,
3689             int load_cert)
3690 {
3691     CK_OBJECT_CLASS cls;
3692     CK_OBJECT_HANDLE obj;
3693     CK_ATTRIBUTE attrs[4];
3694     CK_ULONG count;
3695     CK_CERTIFICATE_TYPE certtype;
3696     CK_BYTE_PTR cert = NULL, cert_id = NULL;
3697     const unsigned char *cp;
3698     int i, r;
3699     unsigned int nattrs;
3700     X509 *x = NULL;
3701 
3702     cls = CKO_CERTIFICATE;
3703     attrs[0].type = CKA_CLASS;
3704     attrs[0].pValue = &cls;
3705     attrs[0].ulValueLen = sizeof cls;
3706 
3707     certtype = CKC_X_509;
3708     attrs[1].type = CKA_CERTIFICATE_TYPE;
3709     attrs[1].pValue = &certtype;
3710     attrs[1].ulValueLen = sizeof certtype;
3711 
3712     nattrs = 2;
3713 
3714     /* If a cert id and/or label were given, use them too */
3715     if (id_cryptoctx->cert_id_len > 0) {
3716         attrs[nattrs].type = CKA_ID;
3717         attrs[nattrs].pValue = id_cryptoctx->cert_id;
3718         attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
3719         nattrs++;
3720     }
3721     if (id_cryptoctx->cert_label != NULL) {
3722         attrs[nattrs].type = CKA_LABEL;
3723         attrs[nattrs].pValue = id_cryptoctx->cert_label;
3724         attrs[nattrs].ulValueLen = strlen(id_cryptoctx->cert_label);
3725         nattrs++;
3726     }
3727 
3728     r = id_cryptoctx->p11->C_FindObjectsInit(session, attrs, nattrs);
3729     if (r != CKR_OK) {
3730         pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r));
3731         krb5_set_error_message(context, EINVAL,
3732                                gettext("PKCS11 error from C_FindObjectsInit: %s"),
3733                                pkinit_pkcs11_code_to_text(r));
3734         r = EINVAL;
3735         goto out;
3736     }
3737 
3738     for (i = 0; ; i++) {
3739         if (i >= MAX_CREDS_ALLOWED) {
3740             r = EINVAL;
3741             goto out;
3742         }
3743 
3744         /* Look for x.509 cert */
3745         /* Solaris Kerberos */
3746         if ((r = id_cryptoctx->p11->C_FindObjects(session, &obj, 1, &count))
3747             != CKR_OK || count == 0) {
3748             id_cryptoctx->creds[i] = NULL;
3749             break;
3750         }
3751 
3752         /* Get cert and id len */
3753         attrs[0].type = CKA_VALUE;
3754         attrs[0].pValue = NULL;
3755         attrs[0].ulValueLen = 0;
3756 
3757         attrs[1].type = CKA_ID;
3758         attrs[1].pValue = NULL;
3759         attrs[1].ulValueLen = 0;
3760 
3761         if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
3762                                                         obj,
3763                                                         attrs,
3764                                                         2)) != CKR_OK &&
3765             r != CKR_BUFFER_TOO_SMALL) {
3766             pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
3767             krb5_set_error_message(context, EINVAL,
3768                                    gettext("Error from PKCS11 C_GetAttributeValue: %s"),
3769                                    pkinit_pkcs11_code_to_text(r));
3770             r = EINVAL;
3771             goto out;
3772         }
3773         cert = malloc((size_t) attrs[0].ulValueLen + 1);
3774         if (cert == NULL) {
3775             r = ENOMEM;
3776             goto out;
3777         }
3778         cert_id = malloc((size_t) attrs[1].ulValueLen + 1);
3779         if (cert_id == NULL) {
3780             r = ENOMEM;
3781             goto out;
3782         }
3783 
3784         /* Read the cert and id off the card */
3785 
3786         attrs[0].type = CKA_VALUE;
3787         attrs[0].pValue = cert;
3788 
3789         attrs[1].type = CKA_ID;
3790         attrs[1].pValue = cert_id;
3791 
3792         if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
3793                 obj, attrs, 2)) != CKR_OK) {
3794             pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
3795             krb5_set_error_message(context, EINVAL,
3796                                    gettext("Error from PKCS11 C_GetAttributeValue: %s"),
3797                                    pkinit_pkcs11_code_to_text(r));
3798             r = EINVAL;
3799             goto out;
3800         }
3801 
3802         pkiDebug("cert %d size %d id %d idlen %d\n", i,
3803             (int) attrs[0].ulValueLen, (int) cert_id[0],
3804             (int) attrs[1].ulValueLen);
3805 
3806         cp = (unsigned char *) cert;
3807         x = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
3808         if (x == NULL) {
3809             r = EINVAL;
3810             goto out;
3811         }
3812 
3813         id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
3814         if (id_cryptoctx->creds[i] == NULL) {
3815             r = ENOMEM;
3816             goto out;
3817         }
3818         id_cryptoctx->creds[i]->cert = x;
3819         id_cryptoctx->creds[i]->key = NULL;
3820         id_cryptoctx->creds[i]->cert_id = cert_id;
3821         cert_id = NULL;
3822         id_cryptoctx->creds[i]->cert_id_len = attrs[1].ulValueLen;
3823         free(cert);
3824         cert = NULL;
3825     }
3826     id_cryptoctx->p11->C_FindObjectsFinal(session);
3827 
3828     if (id_cryptoctx->creds[0] == NULL || id_cryptoctx->creds[0]->cert == NULL) {
3829         r = ENOENT;
3830     } else if (do_matching){
3831         /*
3832          * Do not let pkinit_cert_matching set the primary cert in id_cryptoctx
3833          * as this will be done later.
3834          */
3835         r = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
3836                                  id_cryptoctx, princ, FALSE);
3837     }
3838 
3839 out:
3840     if ((r != 0 || !load_cert) &&
3841         id_cryptoctx->creds[0] != NULL &&
3842         id_cryptoctx->creds[0]->cert != NULL) {
3843         /*
3844          * If there's an error or load_cert isn't 1 free all the certs loaded
3845          * onto id_cryptoctx.
3846          */
3847         (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
3848                                      id_cryptoctx);
3849     }
3850 
3851     if (cert)
3852         free(cert);
3853 
3854     if (cert_id)
3855         free(cert_id);
3856     
3857     return (r);
3858 }
3859 
3860 /*
3861  * Solaris Kerberos: this function has been significantly modified to prompt
3862  * the user in certain cases so defer to this version when resyncing MIT code.
3863  *
3864  * pkinit_open_session now does several things including prompting the user if
3865  * do_matching is set which indicates the code is executing in a client
3866  * context.  This function fills out a pkinit_identity_crypto_context with a
3867  * set of certs and a open session if a token can be found that matches all
3868  * supplied criteria.  If no token is found then the user is prompted one time
3869  * to insert their token.  If there is more than one token that matches all
3870  * client criteria the user is prompted to make a choice if in client context.
3871  * If do_matching is false (KDC context) then the first token matching all
3872  * server criteria is chosen.
3873  */
3874 static krb5_error_code
3875 pkinit_open_session(krb5_context context,
3876                     pkinit_plg_crypto_context plg_cryptoctx,
3877                     pkinit_req_crypto_context req_cryptoctx,
3878                     pkinit_identity_crypto_context cctx,
3879                     krb5_principal princ,
3880                     int do_matching)
3881 {
3882     int i, r;
3883     CK_ULONG count = 0;
3884     CK_SLOT_ID_PTR slotlist = NULL, tmpslotlist = NULL;
3885     CK_TOKEN_INFO tinfo;
3886     krb5_boolean tokenmatch = FALSE;
3887     CK_SESSION_HANDLE tmpsession = NULL;
3888     struct _token_choices token_choices;
3889     int choice = 0;
3890 
3891     if (cctx->session != CK_INVALID_HANDLE)
3892         return 0; /* session already open */
3893 
3894     /* Load module */
3895     if (cctx->p11_module == NULL) {
3896         cctx->p11_module =
3897             pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11);
3898         if (cctx->p11_module == NULL)
3899             return KRB5KDC_ERR_PREAUTH_FAILED;
3900     }
3901 
3902     /* Init */
3903     /* Solaris Kerberos: Don't fail if cryptoki is already initialized */
3904     r = cctx->p11->C_Initialize(NULL);
3905     if (r != CKR_OK && r != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
3906         pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r));
3907         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3908                                gettext("Error from PKCS11 C_Initialize: %s"),
3909                                pkinit_pkcs11_code_to_text(r));
3910         return KRB5KDC_ERR_PREAUTH_FAILED;
3911     }
3912 
3913     (void) memset(&token_choices, 0, sizeof(token_choices));
3914 
3915     /*
3916      * Solaris Kerberos:
3917      * If C_Initialize was already called by the process before the pkinit
3918      * module was loaded then record that fact.
3919      * "finalize_pkcs11" is used by pkinit_fini_pkcs11 to determine whether
3920      * or not C_Finalize() should be called. 
3921      */
3922      cctx->finalize_pkcs11 =
3923         (r == CKR_CRYPTOKI_ALREADY_INITIALIZED ? FALSE : TRUE);
3924     /*
3925      * First make sure that is an applicable slot otherwise fail.
3926      *
3927      * Start by getting a count of all slots with or without tokens.
3928      */
3929 
3930     if ((r = cctx->p11->C_GetSlotList(FALSE, NULL, &count)) != CKR_OK) {
3931         pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
3932         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3933             gettext("Error trying to get PKCS11 slot list: %s"),
3934             pkinit_pkcs11_code_to_text(r));
3935         r = KRB5KDC_ERR_PREAUTH_FAILED;
3936         goto out;
3937     }
3938 
3939     if (count == 0) {
3940         /* There are no slots so bail */
3941         r = KRB5KDC_ERR_PREAUTH_FAILED;
3942         krb5_set_error_message(context, r,
3943                                gettext("No PKCS11 slots found"));
3944         pkiDebug("pkinit_open_session: no slots, count: %d\n", count);
3945         goto out;
3946     } else if (cctx->slotid != PK_NOSLOT) {
3947         /* See if any of the slots match the specified slotID */
3948         tmpslotlist = malloc(count * sizeof (CK_SLOT_ID));
3949         if (tmpslotlist == NULL) {
3950             krb5_set_error_message(context, ENOMEM,
3951                                    gettext("Memory allocation error:"));
3952             r = KRB5KDC_ERR_PREAUTH_FAILED;
3953             goto out;
3954         }
3955         if ((r = cctx->p11->C_GetSlotList(FALSE, tmpslotlist, &count)) != CKR_OK) {
3956             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3957                                    gettext("Error trying to get PKCS11 slot list: %s"),
3958                                    pkinit_pkcs11_code_to_text(r));
3959             pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
3960             r = KRB5KDC_ERR_PREAUTH_FAILED;
3961             goto out;
3962         }
3963 
3964         for (i = 0; i < count && cctx->slotid != tmpslotlist[i]; i++)
3965             continue;
3966 
3967         if (i >= count) {
3968             /* no slots match */
3969             r = KRB5KDC_ERR_PREAUTH_FAILED;
3970             krb5_set_error_message(context, r,
3971                                    gettext("Requested PKCS11 slot ID %d not found"),
3972                                    cctx->slotid);
3973             pkiDebug("open_session: no matching slot found for slotID %d\n",
3974                      cctx->slotid);
3975             goto out;
3976         }
3977     }
3978     
3979 tryagain:
3980     /* get count of slots that have tokens */
3981     if ((r = cctx->p11->C_GetSlotList(TRUE, NULL, &count)) != CKR_OK) {
3982         pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
3983         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3984                                gettext("Error trying to get PKCS11 slot list: %s"),
3985                                pkinit_pkcs11_code_to_text(r));
3986         r = KRB5KDC_ERR_PREAUTH_FAILED;
3987         goto out;
3988     }
3989 
3990     if (count == 0) {
3991         /*
3992          * Note, never prompt if !do_matching as this implies KDC side
3993          * processing
3994          */
3995         if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
3996             /* found slot(s) but no token so prompt and try again */
3997             if ((r = pkinit_prompt_token(context, cctx)) == 0) {
3998                 cctx->p11flags |= C_PROMPTED_USER;
3999                 goto tryagain;
4000             } else {
4001                 pkiDebug("open_session: prompt for token/smart card failed\n");
4002                 krb5_set_error_message(context, r,
4003                                        gettext("Prompt for token/smart card failed"));
4004                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4005                 goto out;
4006             }
4007 
4008         } else {
4009             /* already prompted once so bailing */
4010             r = KRB5KDC_ERR_PREAUTH_FAILED;
4011             krb5_set_error_message(context, r,
4012                                    gettext("No smart card tokens found"));
4013             pkiDebug("pkinit_open_session: no token, already prompted\n");
4014             goto out;
4015         }
4016     }
4017 
4018     if (slotlist != NULL)
4019         free(slotlist);
4020  
4021     slotlist = malloc(count * sizeof (CK_SLOT_ID));
4022     if (slotlist == NULL) {
4023         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4024                                gettext("Memory allocation error"));
4025         r = KRB5KDC_ERR_PREAUTH_FAILED;
4026         goto out;
4027     }
4028     /*
4029      * Solaris Kerberos: get list of PKCS11 slotid's that have tokens.
4030      */
4031     if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
4032         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4033                                gettext("Error trying to get PKCS11 slot list: %s"),
4034                                pkinit_pkcs11_code_to_text(r));
4035         pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4036         r = KRB5KDC_ERR_PREAUTH_FAILED;
4037         goto out;
4038     }
4039 
4040     token_choices.numtokens = 0;
4041     token_choices.token_array = malloc(count * sizeof (*token_choices.token_array));
4042     if (token_choices.token_array == NULL) {
4043         r = KRB5KDC_ERR_PREAUTH_FAILED;
4044         krb5_set_error_message(context, r,
4045                                gettext("Memory allocation error"));
4046         goto out;
4047     }
4048 
4049     /* examine all the tokens */
4050     for (i = 0; i < count; i++) {
4051         /*
4052          * Solaris Kerberos: if a slotid was specified skip slots that don't
4053          * match.
4054          */
4055         if (cctx->slotid != PK_NOSLOT && cctx->slotid != slotlist[i])
4056             continue;
4057 
4058         /* Open session */
4059         if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
4060                                           NULL, NULL, &tmpsession)) != CKR_OK) {
4061             pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r));
4062             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4063                                    gettext("Error trying to open PKCS11 session: %s"),
4064                                    pkinit_pkcs11_code_to_text(r));
4065             r = KRB5KDC_ERR_PREAUTH_FAILED;
4066             goto out;
4067         }
4068 
4069         /* Get token info */
4070         if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) {
4071             pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r));
4072             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4073                                    gettext("Error trying to read PKCS11 token: %s"),
4074                                    pkinit_pkcs11_code_to_text(r));
4075             r = KRB5KDC_ERR_PREAUTH_FAILED;
4076             cctx->p11->C_CloseSession(tmpsession);
4077             goto out;
4078         }
4079 
4080         if (cctx->token_label == NULL) {
4081             /*
4082              * If the token doesn't require login to examine the certs then
4083              * let's check the certs out to see if any match the criteria if
4084              * any.
4085              */
4086             if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4087                 /*
4088                  * It's okay to check the certs if we don't have to login but
4089                  * don't load the certs onto cctx at this point, this will be
4090                  * done later in this function for the chosen token.
4091                  */
4092                 if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4093                                           req_cryptoctx, cctx, princ,
4094                                           do_matching, 0)) == 0) {
4095                     tokenmatch = TRUE;
4096                 } else if (r != ENOENT){
4097                     r = KRB5KDC_ERR_PREAUTH_FAILED;
4098                     cctx->p11->C_CloseSession(tmpsession);
4099                     goto out;
4100                 } else {
4101                     /* ignore ENOENT here */
4102                     r = 0;
4103                 }
4104             } else {
4105                 tokenmatch = TRUE;
4106             }
4107         } else {
4108             /* + 1 so tokenlabelstr can be \0 terminated */
4109             char tokenlabelstr[sizeof (tinfo.label) + 1];
4110 
4111             /*
4112              * Convert token label into C string with trailing white space
4113              * trimmed.
4114              */
4115             trim_token_label(&tinfo, tokenlabelstr, sizeof (tokenlabelstr));
4116 
4117             pkiDebug("open_session: slotid %d token found: \"%s\", "
4118                      "cctx->token_label: \"%s\"\n",
4119                      slotlist[i], tokenlabelstr, (char *) cctx->token_label);
4120 
4121             if (!strcmp(cctx->token_label, tokenlabelstr)) {
4122                 if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4123                     /*
4124                      * It's okay to check the certs if we don't have to login but
4125                      * don't load the certs onto cctx at this point, this will be
4126                      * done later in this function for the chosen token.
4127                      */
4128                     if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4129                                               req_cryptoctx, cctx, princ,
4130                                               do_matching, 0)) == 0) {
4131                         tokenmatch = TRUE;
4132                     } else if (r != ENOENT){
4133                         r = KRB5KDC_ERR_PREAUTH_FAILED;
4134                         cctx->p11->C_CloseSession(tmpsession);
4135                         goto out;
4136                     } else {
4137                         /* ignore ENOENT here */
4138                         r = 0;
4139                     }
4140                 } else {
4141                     tokenmatch = TRUE;
4142                 }
4143             }
4144         }
4145 
4146         if (tokenmatch == TRUE) {
4147             /* add the token to token_choices.token_array */
4148             token_choices.token_array[token_choices.numtokens].slotID = slotlist[i];
4149             token_choices.token_array[token_choices.numtokens].session = tmpsession;
4150             token_choices.token_array[token_choices.numtokens].token_info = tinfo;
4151             token_choices.numtokens++;
4152             /* !do_matching implies we take the first matching token */
4153             if (!do_matching)
4154                 break;
4155             else
4156                 tokenmatch = FALSE;
4157         } else {
4158             cctx->p11->C_CloseSession(tmpsession);
4159         }
4160     }
4161 
4162     if (token_choices.numtokens == 0) {
4163         /*
4164          * Solaris Kerberos: prompt for token one time if there was no token
4165          * and do_matching is 1 (see earlier comment about do_matching).
4166          */
4167         if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4168             if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4169                 cctx->p11flags |= C_PROMPTED_USER;
4170                 goto tryagain;
4171             } else {
4172                 pkiDebug("open_session: prompt for token/smart card failed\n");
4173                 krb5_set_error_message(context, r,
4174                                        gettext("Prompt for token/smart card failed"));
4175                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4176                 goto out;
4177             }
4178         } else {
4179             r = KRB5KDC_ERR_PREAUTH_FAILED;
4180             krb5_set_error_message(context, r,
4181                                    gettext("No smart card tokens found"));
4182             pkiDebug("open_session: no matching token found\n");
4183             goto out;
4184         }
4185     } else if (token_choices.numtokens == 1) {
4186         if ((token_choices.token_array[0].token_info.flags & CKF_LOGIN_REQUIRED) &&
4187             !(cctx->p11flags & C_PROMPTED_USER) &&
4188             do_matching) {
4189             if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4190                 pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4191                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4192                 krb5_set_error_message(context, r,
4193                                        gettext("Prompt for token/smart card failed"));
4194                 goto out;
4195             }
4196             if (choice == RESCAN_TOKENS) {
4197                 /* rescan for new smartcard/token */
4198                 for (i = 0; i < token_choices.numtokens; i++) {
4199                     /* close all sessions */
4200                     cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4201                 }
4202                 free(token_choices.token_array);
4203                 token_choices.token_array = NULL;
4204                 token_choices.numtokens = 0;
4205                 goto tryagain;
4206             } else if (choice == SKIP_TOKENS) {
4207                 /* do not use smartcard/token for auth */
4208                 cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4209                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4210                 goto out;
4211             } else {
4212                 cctx->p11flags |= C_PROMPTED_USER;
4213             }
4214         } else {
4215             choice = 0; /* really the only choice is the first token_array entry */
4216         }
4217     } else if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4218         /* > 1 token so present menu of token choices, let the user decide. */
4219         if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4220             pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4221             r = KRB5KDC_ERR_PREAUTH_FAILED;
4222             krb5_set_error_message(context, r,
4223                                    gettext("Prompt for token/smart card failed"));
4224             goto out;
4225         }
4226         if (choice == RESCAN_TOKENS) {
4227             /* rescan for new smartcard/token */
4228             for (i = 0; i < token_choices.numtokens; i++) {
4229                 /* close all sessions */
4230                 cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4231             }
4232             free(token_choices.token_array);
4233             token_choices.token_array = NULL;
4234             token_choices.numtokens = 0;
4235             goto tryagain;
4236         } else if (choice == SKIP_TOKENS) {
4237             /* do not use smartcard/token for auth */
4238             cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4239             r = KRB5KDC_ERR_PREAUTH_FAILED;
4240             goto out;
4241         } else {
4242             cctx->p11flags |= C_PROMPTED_USER;
4243         }
4244     } else {
4245         r = KRB5KDC_ERR_PREAUTH_FAILED;
4246         goto out;
4247     }
4248 
4249     cctx->slotid = token_choices.token_array[choice].slotID;
4250     cctx->session = token_choices.token_array[choice].session;
4251 
4252     pkiDebug("open_session: slotid %d (%d of %d)\n", (int) cctx->slotid,
4253              i + 1, (int) count);
4254 
4255     /* Login if needed */
4256     /* Solaris Kerberos: added cctx->p11flags check */
4257     if ((token_choices.token_array[choice].token_info.flags & CKF_LOGIN_REQUIRED) &&
4258         !(cctx->p11flags & C_LOGIN_DONE)) {
4259         r = pkinit_login(context, cctx, &token_choices.token_array[choice].token_info);
4260     }
4261 
4262     if (r == 0) {
4263         /* Doing this again to load the certs into cctx. */
4264         r = check_load_certs(context, cctx->session, plg_cryptoctx,
4265                              req_cryptoctx, cctx, princ, do_matching, 1);
4266     }
4267 
4268 out:
4269     if (slotlist != NULL)
4270         free(slotlist);
4271 
4272     if (tmpslotlist != NULL)
4273         free(tmpslotlist);
4274 
4275     if (token_choices.token_array != NULL) {
4276         if (r != 0) {
4277             /* close all sessions if there's an error */
4278             for (i = 0; i < token_choices.numtokens; i++) {
4279                 cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4280             }
4281             cctx->session = CK_INVALID_HANDLE;
4282         } else {
4283             /* close sessions not chosen */
4284             for (i = 0; i < token_choices.numtokens; i++) {
4285                 if (i != choice) {
4286                     cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4287                 }
4288             }
4289         }
4290         free(token_choices.token_array);
4291     }
4292 
4293     return (r);
4294 }
4295 
4296 /*
4297  * Look for a key that's:
4298  * 1. private
4299  * 2. capable of the specified operation (usually signing or decrypting)
4300  * 3. RSA (this may be wrong but it's all we can do for now)
4301  * 4. matches the id of the cert we chose
4302  *
4303  * You must call pkinit_get_certs before calling pkinit_find_private_key
4304  * (that's because we need the ID of the private key)
4305  *
4306  * pkcs11 says the id of the key doesn't have to match that of the cert, but
4307  * I can't figure out any other way to decide which key to use.
4308  *
4309  * We should only find one key that fits all the requirements.
4310  * If there are more than one, we just take the first one.
4311  */
4312 
4313 /* ARGSUSED */
4314 krb5_error_code
4315 pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
4316                         CK_ATTRIBUTE_TYPE usage,
4317                         CK_OBJECT_HANDLE *objp)
4318 {
4319     CK_OBJECT_CLASS cls;
4320     CK_ATTRIBUTE attrs[4];
4321     CK_ULONG count;
4322     CK_KEY_TYPE keytype;
4323     unsigned int nattrs = 0;
4324     int r;
4325 #ifdef PKINIT_USE_KEY_USAGE
4326     CK_BBOOL true_false;
4327 #endif
4328 
4329     cls = CKO_PRIVATE_KEY;
4330     attrs[nattrs].type = CKA_CLASS;
4331     attrs[nattrs].pValue = &cls;
4332     attrs[nattrs].ulValueLen = sizeof cls;
4333     nattrs++;
4334 
4335 #ifdef PKINIT_USE_KEY_USAGE
4336     /*
4337      * Some cards get confused if you try to specify a key usage,
4338      * so don't, and hope for the best. This will fail if you have
4339      * several keys with the same id and different usages but I have
4340      * not seen this on real cards.
4341      */
4342     true_false = TRUE;
4343     attrs[nattrs].type = usage;
4344     attrs[nattrs].pValue = &true_false;
4345     attrs[nattrs].ulValueLen = sizeof true_false;
4346     nattrs++;
4347 #endif
4348 
4349     keytype = CKK_RSA;
4350     attrs[nattrs].type = CKA_KEY_TYPE;
4351     attrs[nattrs].pValue = &keytype;
4352     attrs[nattrs].ulValueLen = sizeof keytype;
4353     nattrs++;
4354 
4355     attrs[nattrs].type = CKA_ID;
4356     attrs[nattrs].pValue = id_cryptoctx->cert_id;
4357     attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
4358     nattrs++;
4359 
4360     r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4361     if (r != CKR_OK) {
4362         pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4363                  pkinit_pkcs11_code_to_text(r));
4364         return KRB5KDC_ERR_PREAUTH_FAILED;
4365     }
4366 
4367     r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4368     id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4369     pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4370 
4371     /*
4372      * Solaris Kerberos:
4373      * The CKA_ID may not be correctly set for the private key. For e.g. when
4374      * storing a private key in softtoken pktool(1) doesn't generate or store
4375      * a CKA_ID for the private key. Another way to identify the private key is
4376      * to look for a private key with the same RSA modulus as the public key
4377      * in the certificate.
4378      */
4379     if (r == CKR_OK && count != 1) {
4380 
4381         EVP_PKEY *priv;
4382         X509 *cert;
4383         unsigned int n_len;
4384         unsigned char *n_bytes;
4385 
4386         cert = sk_X509_value(id_cryptoctx->my_certs, 0);
4387         priv = X509_get_pubkey(cert);
4388         if (priv == NULL) {
4389                 pkiDebug("Failed to extract pub key from cert\n");
4390                 return KRB5KDC_ERR_PREAUTH_FAILED;
4391         }
4392 
4393         nattrs = 0;
4394         cls = CKO_PRIVATE_KEY;
4395         attrs[nattrs].type = CKA_CLASS;
4396         attrs[nattrs].pValue = &cls;
4397         attrs[nattrs].ulValueLen = sizeof cls;
4398         nattrs++;
4399 
4400 #ifdef PKINIT_USE_KEY_USAGE
4401         true_false = TRUE;
4402         attrs[nattrs].type = usage;
4403         attrs[nattrs].pValue = &true_false;
4404         attrs[nattrs].ulValueLen = sizeof true_false;
4405         nattrs++;
4406 #endif
4407 
4408         keytype = CKK_RSA;
4409         attrs[nattrs].type = CKA_KEY_TYPE;
4410         attrs[nattrs].pValue = &keytype;
4411         attrs[nattrs].ulValueLen = sizeof keytype;
4412         nattrs++;
4413 
4414         n_len = BN_num_bytes(priv->pkey.rsa->n);
4415         n_bytes = (unsigned char *) malloc((size_t) n_len);
4416         if (n_bytes == NULL) {
4417                 return (ENOMEM);
4418         }
4419 
4420         if (BN_bn2bin(priv->pkey.rsa->n, n_bytes) == 0) {
4421                 free (n_bytes);
4422                 pkiDebug("zero-byte key modulus\n");
4423                 return KRB5KDC_ERR_PREAUTH_FAILED;
4424         }
4425 
4426         attrs[nattrs].type = CKA_MODULUS;
4427         attrs[nattrs].ulValueLen = n_len; 
4428         attrs[nattrs].pValue = n_bytes;
4429 
4430         nattrs++;
4431 
4432         r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4433         free (n_bytes);
4434         if (r != CKR_OK) {
4435                 pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4436                         pkinit_pkcs11_code_to_text(r));
4437                 return KRB5KDC_ERR_PREAUTH_FAILED;
4438         }
4439 
4440         r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4441         id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4442         pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4443 
4444     }
4445 
4446     if (r != CKR_OK || count < 1)
4447         return KRB5KDC_ERR_PREAUTH_FAILED;
4448     return 0;
4449 }
4450 #endif
4451 
4452 /* ARGSUSED */
4453 static krb5_error_code
4454 pkinit_decode_data_fs(krb5_context context,
4455                       pkinit_identity_crypto_context id_cryptoctx,
4456                       unsigned char *data,
4457                       unsigned int data_len,
4458                       unsigned char **decoded_data,
4459                       unsigned int *decoded_data_len)
4460 {
4461     if (decode_data(decoded_data, decoded_data_len, data, data_len,
4462                 id_cryptoctx->my_key, sk_X509_value(id_cryptoctx->my_certs,
4463                 id_cryptoctx->cert_index)) <= 0) {
4464         pkiDebug("failed to decode data\n");
4465         return KRB5KDC_ERR_PREAUTH_FAILED;
4466     }
4467     return 0;
4468 }
4469 
4470 #ifndef WITHOUT_PKCS11
4471 #ifdef SILLYDECRYPT
4472 CK_RV
4473 pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
4474                  CK_BYTE_PTR pEncryptedData,
4475                  CK_ULONG  ulEncryptedDataLen,
4476                  CK_BYTE_PTR pData,
4477                  CK_ULONG_PTR pulDataLen)
4478 {
4479     CK_RV rv = CKR_OK;
4480 
4481     rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
4482         ulEncryptedDataLen, pData, pulDataLen);
4483     if (rv == CKR_OK) {
4484         pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
4485     }
4486     return rv;
4487 }
4488 #endif
4489 
4490 static krb5_error_code
4491 pkinit_decode_data_pkcs11(krb5_context context,
4492                           pkinit_identity_crypto_context id_cryptoctx,
4493                           unsigned char *data,
4494                           unsigned int data_len,
4495                           unsigned char **decoded_data,
4496                           unsigned int *decoded_data_len)
4497 {
4498     CK_OBJECT_HANDLE obj;
4499     CK_ULONG len;
4500     CK_MECHANISM mech;
4501     unsigned char *cp;
4502     int r;
4503 
4504     /*
4505      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4506      * loaded.
4507      */
4508     assert(id_cryptoctx->p11 != NULL);
4509 
4510     /* Solaris Kerberos: Login, if needed, to access private object */
4511     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
4512         CK_TOKEN_INFO tinfo;
4513 
4514         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
4515         if (r != 0)
4516             return r;
4517 
4518         r = pkinit_login(context, id_cryptoctx, &tinfo);
4519         if (r != 0)
4520             return r;
4521     }
4522 
4523     r = pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj);
4524     if (r != 0)
4525         return r;
4526 
4527     mech.mechanism = CKM_RSA_PKCS;
4528     mech.pParameter = NULL;
4529     mech.ulParameterLen = 0;
4530 
4531     if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech,
4532             obj)) != CKR_OK) {
4533         pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
4534         return KRB5KDC_ERR_PREAUTH_FAILED;
4535     }
4536     pkiDebug("data_len = %d\n", data_len);
4537     cp = (unsigned char *)malloc((size_t) data_len);
4538     if (cp == NULL)
4539         return ENOMEM;
4540     len = data_len;
4541 #ifdef SILLYDECRYPT
4542     pkiDebug("session %x edata %x edata_len %d data %x datalen @%x %d\n",
4543             (int) id_cryptoctx->session, (int) data, (int) data_len, (int) cp,
4544             (int) &len, (int) len);
4545     if ((r = pkinit_C_Decrypt(id_cryptoctx, data, (CK_ULONG) data_len,
4546             cp, &len)) != CKR_OK) {
4547 #else
4548     if ((r = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, data,
4549             (CK_ULONG) data_len, cp, &len)) != CKR_OK) {
4550 #endif
4551         pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
4552         if (r == CKR_BUFFER_TOO_SMALL)
4553             pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
4554         return KRB5KDC_ERR_PREAUTH_FAILED;
4555     }
4556     pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
4557     *decoded_data_len = len;
4558     *decoded_data = cp;
4559 
4560     return 0;
4561 }
4562 #endif
4563 
4564 krb5_error_code
4565 pkinit_decode_data(krb5_context context,
4566                    pkinit_identity_crypto_context id_cryptoctx,
4567                    unsigned char *data,
4568                    unsigned int data_len,
4569                    unsigned char **decoded_data,
4570                    unsigned int *decoded_data_len)
4571 {
4572     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4573 
4574     if (id_cryptoctx->pkcs11_method != 1)
4575         retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len,
4576             decoded_data, decoded_data_len);
4577 #ifndef WITHOUT_PKCS11
4578     else
4579         retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data,
4580             data_len, decoded_data, decoded_data_len);
4581 #endif
4582 
4583     return retval;
4584 }
4585 
4586 /* ARGSUSED */
4587 static krb5_error_code
4588 pkinit_sign_data_fs(krb5_context context,
4589                  pkinit_identity_crypto_context id_cryptoctx,
4590                  unsigned char *data,
4591                  unsigned int data_len,
4592                  unsigned char **sig,
4593                  unsigned int *sig_len)
4594 {
4595     if (create_signature(sig, sig_len, data, data_len,
4596             id_cryptoctx->my_key) != 0) {
4597             pkiDebug("failed to create the signature\n");
4598             return KRB5KDC_ERR_PREAUTH_FAILED;
4599     }
4600     return 0;
4601 }
4602 
4603 #ifndef WITHOUT_PKCS11
4604 static krb5_error_code
4605 pkinit_sign_data_pkcs11(krb5_context context,
4606                         pkinit_identity_crypto_context id_cryptoctx,
4607                         unsigned char *data,
4608                         unsigned int data_len,
4609                         unsigned char **sig,
4610                         unsigned int *sig_len)
4611 {
4612     CK_OBJECT_HANDLE obj;
4613     CK_ULONG len;
4614     CK_MECHANISM mech;
4615     unsigned char *cp;
4616     int r;
4617 
4618     /*
4619      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4620      * loaded.
4621      */
4622     assert(id_cryptoctx->p11 != NULL);
4623 
4624     /* Solaris Kerberos: Login, if needed, to access private object */
4625     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
4626         CK_TOKEN_INFO tinfo;
4627 
4628         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
4629         if (r != 0)
4630             return r;
4631 
4632         r = pkinit_login(context, id_cryptoctx, &tinfo);
4633         if (r != 0)
4634             return r;
4635     }
4636 
4637     r = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
4638     if (r != 0 )
4639         return r;
4640 
4641     mech.mechanism = id_cryptoctx->mech;
4642     mech.pParameter = NULL;
4643     mech.ulParameterLen = 0;
4644 
4645     if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
4646             obj)) != CKR_OK) {
4647         pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r));
4648         return KRB5KDC_ERR_PREAUTH_FAILED;
4649     }
4650 
4651     /*
4652      * Key len would give an upper bound on sig size, but there's no way to
4653      * get that. So guess, and if it's too small, re-malloc.
4654      */
4655     len = PK_SIGLEN_GUESS;
4656     cp = (unsigned char *)malloc((size_t) len);
4657     if (cp == NULL)
4658         return ENOMEM;
4659 
4660     r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4661                                  (CK_ULONG) data_len, cp, &len);
4662     if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
4663         free(cp);
4664         pkiDebug("C_Sign realloc %d\n", (int) len);
4665         cp = (unsigned char *)malloc((size_t) len);
4666         r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4667                                      (CK_ULONG) data_len, cp, &len);
4668     }
4669     if (r != CKR_OK) {
4670         pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r));
4671         return KRB5KDC_ERR_PREAUTH_FAILED;
4672     }
4673     pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
4674     *sig_len = len;
4675     *sig = cp;
4676 
4677     return 0;
4678 }
4679 #endif
4680 
4681 krb5_error_code
4682 pkinit_sign_data(krb5_context context,
4683                  pkinit_identity_crypto_context id_cryptoctx,
4684                  unsigned char *data,
4685                  unsigned int data_len,
4686                  unsigned char **sig,
4687                  unsigned int *sig_len)
4688 {
4689     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4690 
4691     if (id_cryptoctx == NULL || id_cryptoctx->pkcs11_method != 1)
4692         retval = pkinit_sign_data_fs(context, id_cryptoctx, data, data_len,
4693                                      sig, sig_len);
4694 #ifndef WITHOUT_PKCS11
4695     else
4696         retval = pkinit_sign_data_pkcs11(context, id_cryptoctx, data, data_len,
4697                                          sig, sig_len);
4698 #endif
4699 
4700     return retval;
4701 }
4702 
4703 
4704 static krb5_error_code
4705 decode_data(unsigned char **out_data, unsigned int *out_data_len,
4706             unsigned char *data, unsigned int data_len,
4707             EVP_PKEY *pkey, X509 *cert)
4708 {
4709     /* Solaris Kerberos */
4710     int len;
4711     unsigned char *buf = NULL;
4712     int buf_len = 0;
4713 
4714     /* Solaris Kerberos */
4715     if (out_data == NULL || out_data_len == NULL)
4716         return EINVAL;
4717 
4718     if (cert && !X509_check_private_key(cert, pkey)) {
4719         pkiDebug("private key does not match certificate\n");
4720         /* Solaris Kerberos */
4721         return EINVAL;
4722     }
4723 
4724     buf_len = EVP_PKEY_size(pkey);
4725     buf = (unsigned char *)malloc((size_t) buf_len + 10);
4726     if (buf == NULL)
4727         return ENOMEM;
4728 
4729 #if OPENSSL_VERSION_NUMBER < 0x10000000L
4730     len = EVP_PKEY_decrypt(buf, data, (int)data_len, pkey);
4731 #else
4732     len = EVP_PKEY_decrypt_old(buf, data, (int)data_len, pkey);
4733 #endif
4734     if (len <= 0) {
4735         pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
4736         /* Solaris Kerberos */
4737         free(buf);
4738         return KRB5KRB_ERR_GENERIC;
4739     }
4740     *out_data = buf;
4741     *out_data_len = len;
4742 
4743     return 0;
4744 }
4745 
4746 static krb5_error_code
4747 create_signature(unsigned char **sig, unsigned int *sig_len,
4748                  unsigned char *data, unsigned int data_len, EVP_PKEY *pkey)
4749 {
4750     krb5_error_code retval = ENOMEM;
4751     EVP_MD_CTX md_ctx;
4752 
4753     if (pkey == NULL)
4754         /* Solaris Kerberos */
4755         return EINVAL;
4756 
4757     EVP_VerifyInit(&md_ctx, EVP_sha1());
4758     EVP_SignUpdate(&md_ctx, data, data_len);
4759     *sig_len = EVP_PKEY_size(pkey);
4760     if ((*sig = (unsigned char *) malloc((size_t) *sig_len)) == NULL)
4761         goto cleanup;
4762     EVP_SignFinal(&md_ctx, *sig, sig_len, pkey);
4763 
4764     retval = 0;
4765 
4766   cleanup:
4767     EVP_MD_CTX_cleanup(&md_ctx);
4768 
4769     return retval;
4770 }
4771 
4772 /*
4773  * Note:
4774  * This is not the routine the KDC uses to get its certificate.
4775  * This routine is intended to be called by the client
4776  * to obtain the KDC's certificate from some local storage
4777  * to be sent as a hint in its request to the KDC.
4778  */
4779 /* ARGSUSED */
4780 krb5_error_code
4781 pkinit_get_kdc_cert(krb5_context context,
4782                     pkinit_plg_crypto_context plg_cryptoctx,
4783                     pkinit_req_crypto_context req_cryptoctx,
4784                     pkinit_identity_crypto_context id_cryptoctx,
4785                     krb5_principal princ)
4786 {
4787    /* Solaris Kerberos */
4788     if (req_cryptoctx == NULL)
4789         return EINVAL;
4790 
4791     req_cryptoctx->received_cert = NULL;
4792     return 0;
4793 }
4794 
4795 /* ARGSUSED */
4796 static krb5_error_code
4797 pkinit_get_certs_pkcs12(krb5_context context,
4798                           pkinit_plg_crypto_context plg_cryptoctx,
4799                           pkinit_req_crypto_context req_cryptoctx,
4800                           pkinit_identity_opts *idopts,
4801                           pkinit_identity_crypto_context id_cryptoctx,
4802                           krb5_principal princ)
4803 {
4804     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4805     X509 *x = NULL;
4806     PKCS12 *p12 = NULL;
4807     int ret;
4808     FILE *fp;
4809     EVP_PKEY *y = NULL;
4810 
4811     if (idopts->cert_filename == NULL) {
4812         /* Solaris Kerberos: Improved error messages */
4813         krb5_set_error_message(context, retval,
4814             gettext("Failed to get certificate location"));
4815         pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
4816         goto cleanup;
4817     }
4818 
4819     if (idopts->key_filename == NULL) {
4820         /* Solaris Kerberos: Improved error messages */
4821         krb5_set_error_message(context, retval,
4822             gettext("Failed to get private key location"));
4823         pkiDebug("%s: failed to get user's private key location\n", __FUNCTION__);
4824         goto cleanup;
4825     }
4826 
4827     fp = fopen(idopts->cert_filename, "rb");
4828     if (fp == NULL) {
4829         /* Solaris Kerberos: Improved error messages */
4830         krb5_set_error_message(context, retval,
4831             gettext("Failed to open PKCS12 file '%s': %s"),
4832             idopts->cert_filename, error_message(errno));
4833         pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
4834                  idopts->cert_filename, errno);
4835         goto cleanup;
4836     }
4837 
4838     p12 = d2i_PKCS12_fp(fp, NULL);
4839     (void) fclose(fp);
4840     if (p12 == NULL) {
4841         krb5_set_error_message(context, retval,
4842             gettext("Failed to decode PKCS12 file '%s' contents"),
4843             idopts->cert_filename);
4844         pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
4845                  idopts->cert_filename);
4846         goto cleanup;
4847     }
4848     /*
4849      * Try parsing with no pass phrase first.  If that fails,
4850      * prompt for the pass phrase and try again.
4851      */
4852     ret = PKCS12_parse(p12, NULL, &y, &x, NULL);
4853     if (ret == 0) {
4854         krb5_data rdat;
4855         krb5_prompt kprompt;
4856         krb5_prompt_type prompt_type;
4857         int r = 0;
4858         char prompt_string[128];
4859         char prompt_reply[128];
4860         /* Solaris Kerberos */
4861         char *prompt_prefix = gettext("Pass phrase for");
4862 
4863         pkiDebug("Initial PKCS12_parse with no password failed\n");
4864 
4865         if (id_cryptoctx->PIN != NULL) {
4866                 /* Solaris Kerberos: use PIN if set */
4867                 rdat.data = id_cryptoctx->PIN;
4868                 /* note rdat.length isn't needed in this case */
4869         } else {
4870                 (void) memset(prompt_reply, '\0', sizeof(prompt_reply));
4871                 rdat.data = prompt_reply;
4872                 rdat.length = sizeof(prompt_reply);
4873 
4874                 r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
4875                              prompt_prefix, idopts->cert_filename);
4876                 if (r >= sizeof(prompt_string)) {
4877                     pkiDebug("Prompt string, '%s %s', is too long!\n",
4878                              prompt_prefix, idopts->cert_filename);
4879                     goto cleanup;
4880                 }
4881                 kprompt.prompt = prompt_string;
4882                 kprompt.hidden = 1;
4883                 kprompt.reply = &rdat;
4884                 prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
4885 
4886                 /* PROMPTER_INVOCATION */
4887                 k5int_set_prompt_types(context, &prompt_type);
4888                 r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
4889                                               NULL, NULL, 1, &kprompt);
4890                 k5int_set_prompt_types(context, NULL);
4891         }
4892 
4893         ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
4894         if (ret == 0) {
4895             /* Solaris Kerberos: Improved error messages */
4896             krb5_set_error_message(context, retval,
4897                 gettext("Failed to parse PKCS12 file '%s' with password"),
4898                 idopts->cert_filename);
4899             pkiDebug("Seconde PKCS12_parse with password failed\n");
4900             goto cleanup;
4901         }
4902     }
4903     id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
4904     if (id_cryptoctx->creds[0] == NULL)
4905         goto cleanup;
4906     id_cryptoctx->creds[0]->cert = x;
4907 #ifndef WITHOUT_PKCS11
4908     id_cryptoctx->creds[0]->cert_id = NULL;
4909     id_cryptoctx->creds[0]->cert_id_len = 0;
4910 #endif
4911     id_cryptoctx->creds[0]->key = y;
4912     id_cryptoctx->creds[1] = NULL;
4913 
4914     retval = 0;
4915 
4916 cleanup:
4917     if (p12)
4918         PKCS12_free(p12);
4919     if (retval) {
4920         if (x != NULL)
4921             X509_free(x);
4922         if (y != NULL)
4923             EVP_PKEY_free(y);
4924     }
4925     return retval;
4926 }
4927 
4928 static krb5_error_code
4929 pkinit_load_fs_cert_and_key(krb5_context context,
4930                             pkinit_identity_crypto_context id_cryptoctx,
4931                             char *certname,
4932                             char *keyname,
4933                             int cindex)
4934 {
4935     krb5_error_code retval;
4936     X509 *x = NULL;
4937     EVP_PKEY *y = NULL;
4938 
4939     /* load the certificate */
4940     retval = get_cert(certname, &x);
4941     if (retval != 0 || x == NULL) {
4942         /* Solaris Kerberos: Improved error messages */
4943         krb5_set_error_message(context, retval,
4944             gettext("Failed to load user's certificate from %s: %s"),
4945                 certname, error_message(retval));
4946         pkiDebug("failed to load user's certificate from '%s'\n", certname);
4947         goto cleanup;
4948     }
4949     retval = get_key(keyname, &y);
4950     if (retval != 0 || y == NULL) {
4951         /* Solaris Kerberos: Improved error messages */
4952         krb5_set_error_message(context, retval,
4953             gettext("Failed to load user's private key from %s: %s"),
4954                 keyname, error_message(retval));
4955         pkiDebug("failed to load user's private key from '%s'\n", keyname);
4956         goto cleanup;
4957     }
4958 
4959     id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
4960     if (id_cryptoctx->creds[cindex] == NULL) {
4961         retval = ENOMEM;
4962         goto cleanup;
4963     }
4964     id_cryptoctx->creds[cindex]->cert = x;
4965 #ifndef WITHOUT_PKCS11
4966     id_cryptoctx->creds[cindex]->cert_id = NULL;
4967     id_cryptoctx->creds[cindex]->cert_id_len = 0;
4968 #endif
4969     id_cryptoctx->creds[cindex]->key = y;
4970     id_cryptoctx->creds[cindex+1] = NULL;
4971 
4972     retval = 0;
4973 
4974 cleanup:
4975     if (retval) {
4976         if (x != NULL)
4977             X509_free(x);
4978         if (y != NULL)
4979             EVP_PKEY_free(y);
4980     }
4981     return retval;
4982 }
4983 
4984 /* ARGSUSED */
4985 static krb5_error_code
4986 pkinit_get_certs_fs(krb5_context context,
4987                           pkinit_plg_crypto_context plg_cryptoctx,
4988                           pkinit_req_crypto_context req_cryptoctx,
4989                           pkinit_identity_opts *idopts,
4990                           pkinit_identity_crypto_context id_cryptoctx,
4991                           krb5_principal princ)
4992 {
4993     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4994 
4995     if (idopts->cert_filename == NULL) {
4996         pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
4997         goto cleanup;
4998     }
4999 
5000     if (idopts->key_filename == NULL) {
5001         pkiDebug("%s: failed to get user's private key location\n",
5002                  __FUNCTION__);
5003         goto cleanup;
5004     }
5005 
5006     retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5007                                          idopts->cert_filename,
5008                                          idopts->key_filename, 0);
5009 cleanup:
5010     return retval;
5011 }
5012 
5013 /* ARGSUSED */
5014 static krb5_error_code
5015 pkinit_get_certs_dir(krb5_context context,
5016                      pkinit_plg_crypto_context plg_cryptoctx,
5017                      pkinit_req_crypto_context req_cryptoctx,
5018                      pkinit_identity_opts *idopts,
5019                      pkinit_identity_crypto_context id_cryptoctx,
5020                      krb5_principal princ)
5021 {
5022     /* Solaris Kerberos */
5023     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
5024     DIR *d = NULL;
5025     struct dirent *dentry = NULL;
5026     char certname[1024];
5027     char keyname[1024];
5028     int i = 0, len;
5029     char *dirname, *suf;
5030 
5031     /* Solaris Kerberos */
5032     if (idopts == NULL)
5033         return EINVAL;
5034 
5035     if (idopts->cert_filename == NULL) {
5036         pkiDebug("%s: failed to get user's certificate directory location\n",
5037                  __FUNCTION__);
5038         return ENOENT;
5039     }
5040 
5041     dirname = idopts->cert_filename;
5042     d = opendir(dirname);
5043     if (d == NULL) {
5044         /* Solaris Kerberos: Improved error messages */
5045         krb5_set_error_message(context, errno,
5046             gettext("Failed to open directory \"%s\": %s"),
5047             dirname, error_message(errno));
5048         return errno;
5049     }
5050 
5051     /*
5052      * We'll assume that certs are named XXX.crt and the corresponding
5053      * key is named XXX.key
5054      */
5055     while ((i < MAX_CREDS_ALLOWED) &&  (dentry = readdir(d)) != NULL) {
5056         /* Ignore subdirectories and anything starting with a dot */
5057 #ifdef DT_DIR
5058         if (dentry->d_type == DT_DIR)
5059             continue;
5060 #endif
5061         if (dentry->d_name[0] == '.')
5062             continue;
5063         len = strlen(dentry->d_name);
5064         if (len < 5)
5065             continue;
5066         suf = dentry->d_name + (len - 4);
5067         if (strncmp(suf, ".crt", 4) != 0)
5068             continue;
5069 
5070         /* Checked length */
5071         if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(certname)) {
5072             pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5073                      __FUNCTION__, dirname, dentry->d_name);
5074             continue;
5075         }
5076         (void) snprintf(certname, sizeof(certname), "%s/%s", dirname, dentry->d_name);
5077         (void) snprintf(keyname, sizeof(keyname), "%s/%s", dirname, dentry->d_name);
5078         len = strlen(keyname);
5079         keyname[len - 3] = 'k';
5080         keyname[len - 2] = 'e';
5081         keyname[len - 1] = 'y';
5082 
5083         retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5084                                              certname, keyname, i);
5085         if (retval == 0) {
5086             pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
5087                      __FUNCTION__, dentry->d_name);
5088             i++;
5089         }
5090         else
5091             continue;
5092     }
5093 
5094     if (i == 0) {
5095         /* Solaris Kerberos: Improved error messages */
5096         krb5_set_error_message(context, ENOENT,
5097             gettext("No suitable cert/key pairs found in directory '%s'"),
5098             idopts->cert_filename);
5099         pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
5100                  __FUNCTION__, idopts->cert_filename);
5101         retval = ENOENT;
5102         goto cleanup;
5103     }
5104 
5105     retval = 0;
5106 
5107   cleanup:
5108     if (d) 
5109         (void) closedir(d);
5110 
5111     return retval;
5112 }
5113 
5114 #ifndef WITHOUT_PKCS11
5115 /* ARGSUSED */
5116 static krb5_error_code
5117 pkinit_get_certs_pkcs11(krb5_context context,
5118                         pkinit_plg_crypto_context plg_cryptoctx,
5119                         pkinit_req_crypto_context req_cryptoctx,
5120                         pkinit_identity_opts *idopts,
5121                         pkinit_identity_crypto_context id_cryptoctx,
5122                         krb5_principal princ,
5123                         int do_matching)
5124 {
5125 #ifdef PKINIT_USE_MECH_LIST
5126     CK_MECHANISM_TYPE_PTR mechp = NULL;
5127     CK_MECHANISM_INFO info;
5128 #endif
5129 
5130     if (id_cryptoctx->p11flags & C_SKIP_PKCS11_AUTH)
5131         return KRB5KDC_ERR_PREAUTH_FAILED;
5132 
5133     /* Copy stuff from idopts -> id_cryptoctx */
5134     if (idopts->p11_module_name != NULL) {
5135         id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
5136         if (id_cryptoctx->p11_module_name == NULL)
5137             return ENOMEM;
5138     }
5139     if (idopts->token_label != NULL) {
5140         id_cryptoctx->token_label = strdup(idopts->token_label);
5141         if (id_cryptoctx->token_label == NULL)
5142             return ENOMEM;
5143     }
5144     if (idopts->cert_label != NULL) {
5145         id_cryptoctx->cert_label = strdup(idopts->cert_label);
5146         if (id_cryptoctx->cert_label == NULL)
5147             return ENOMEM;
5148     }
5149     if (idopts->PIN != NULL) {
5150         id_cryptoctx->PIN = strdup(idopts->PIN);
5151         if (id_cryptoctx->PIN == NULL)
5152             return ENOMEM;
5153     }
5154     /* Convert the ascii cert_id string into a binary blob */
5155     /*
5156      * Solaris Kerberos:
5157      * If the cert_id_string is empty then behave in a similar way to how
5158      * an empty certlabel is treated - i.e. don't fail now but rather continue
5159      * as though the certid wasn't specified.
5160      */
5161     if (idopts->cert_id_string != NULL && strlen(idopts->cert_id_string) != 0) {
5162         BIGNUM *bn = NULL;
5163         BN_hex2bn(&bn, idopts->cert_id_string);
5164         if (bn == NULL)
5165             return ENOMEM;
5166         id_cryptoctx->cert_id_len = BN_num_bytes(bn);
5167         id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
5168         if (id_cryptoctx->cert_id == NULL) {
5169             BN_free(bn);
5170             return ENOMEM;
5171         }
5172         BN_bn2bin(bn, id_cryptoctx->cert_id);
5173         BN_free(bn);
5174     }
5175     id_cryptoctx->slotid = idopts->slotid;
5176     id_cryptoctx->pkcs11_method = 1;
5177 
5178 #ifndef PKINIT_USE_MECH_LIST
5179     /*
5180      * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
5181      * many cards seems to be confused about whether they are capable of
5182      * this or not. The safe thing seems to be to ignore the mechanism list,
5183      * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
5184      */
5185 
5186     id_cryptoctx->mech = CKM_RSA_PKCS;
5187 #else
5188     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL,
5189             &count)) != CKR_OK || count <= 0) {
5190         pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r));
5191         return KRB5KDC_ERR_PREAUTH_FAILED;
5192     }
5193     mechp = (CK_MECHANISM_TYPE_PTR) malloc(count * sizeof (CK_MECHANISM_TYPE));
5194     if (mechp == NULL)
5195         return ENOMEM;
5196     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid,
5197             mechp, &count)) != CKR_OK) {
5198         free(mechp);
5199         return KRB5KDC_ERR_PREAUTH_FAILED;
5200     }
5201     for (i = 0; i < count; i++) {
5202         if ((r = id_cryptoctx->p11->C_GetMechanismInfo(id_cryptoctx->slotid,
5203                 mechp[i], &info)) != CKR_OK) {
5204             free(mechp);
5205             return KRB5KDC_ERR_PREAUTH_FAILED;
5206         }
5207 #ifdef DEBUG_MECHINFO
5208         pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
5209         if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
5210             pkiDebug("  this mech is good for sign & decrypt\n");
5211 #endif
5212         if (mechp[i] == CKM_RSA_PKCS) {
5213             /* This seems backwards... */
5214             id_cryptoctx->mech =
5215                 (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
5216         }
5217     }
5218     free(mechp);
5219 
5220     pkiDebug("got %d mechs from card\n", (int) count);
5221 #endif
5222 
5223     return (pkinit_open_session(context, plg_cryptoctx, req_cryptoctx,
5224                                 id_cryptoctx, princ, do_matching));
5225 }
5226 #endif
5227 
5228 /* ARGSUSED */
5229 static void
5230 free_cred_info(krb5_context context,
5231                pkinit_identity_crypto_context id_cryptoctx,
5232                struct _pkinit_cred_info *cred)
5233 {
5234     if (cred != NULL) {
5235         if (cred->cert != NULL)
5236             X509_free(cred->cert);
5237         if (cred->key != NULL)
5238             EVP_PKEY_free(cred->key);
5239 #ifndef WITHOUT_PKCS11
5240         if (cred->cert_id != NULL)
5241             free(cred->cert_id);
5242 #endif
5243         free(cred);
5244     }
5245 }
5246 
5247 /* ARGSUSED */
5248 krb5_error_code
5249 crypto_free_cert_info(krb5_context context,
5250                       pkinit_plg_crypto_context plg_cryptoctx,
5251                       pkinit_req_crypto_context req_cryptoctx,
5252                       pkinit_identity_crypto_context id_cryptoctx)
5253 {
5254     int i;
5255 
5256     if (id_cryptoctx == NULL)
5257         return EINVAL;
5258 
5259     for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
5260         if (id_cryptoctx->creds[i] != NULL) {
5261             free_cred_info(context, id_cryptoctx, id_cryptoctx->creds[i]);
5262             id_cryptoctx->creds[i] = NULL;
5263         }
5264     }
5265     return 0;
5266 }
5267 
5268 krb5_error_code
5269 crypto_load_certs(krb5_context context,
5270                   pkinit_plg_crypto_context plg_cryptoctx,
5271                   pkinit_req_crypto_context req_cryptoctx,
5272                   pkinit_identity_opts *idopts,
5273                   pkinit_identity_crypto_context id_cryptoctx,
5274                   krb5_principal princ,
5275                   int do_matching)
5276 {
5277     krb5_error_code retval;
5278 
5279     switch(idopts->idtype) {
5280         case IDTYPE_FILE:
5281             retval = pkinit_get_certs_fs(context, plg_cryptoctx,
5282                                          req_cryptoctx, idopts,
5283                                          id_cryptoctx, princ);
5284             break;
5285         case IDTYPE_DIR:
5286             retval = pkinit_get_certs_dir(context, plg_cryptoctx,
5287                                           req_cryptoctx, idopts,
5288                                           id_cryptoctx, princ);
5289             break;
5290 #ifndef WITHOUT_PKCS11
5291         case IDTYPE_PKCS11:
5292             retval = pkinit_get_certs_pkcs11(context, plg_cryptoctx,
5293                                              req_cryptoctx, idopts,
5294                                              id_cryptoctx, princ, do_matching);
5295             break;
5296 #endif
5297         case IDTYPE_PKCS12:
5298             retval = pkinit_get_certs_pkcs12(context, plg_cryptoctx,
5299                                              req_cryptoctx, idopts,
5300                                              id_cryptoctx, princ);
5301                 break;
5302         default:
5303             retval = EINVAL;
5304     }
5305 /* Solaris Kerberos */
5306 
5307     return retval;
5308 }
5309 
5310 /*
5311  * Get number of certificates available after crypto_load_certs()
5312  */
5313 /* ARGSUSED */
5314 krb5_error_code
5315 crypto_cert_get_count(krb5_context context,
5316                       pkinit_plg_crypto_context plg_cryptoctx,
5317                       pkinit_req_crypto_context req_cryptoctx,
5318                       pkinit_identity_crypto_context id_cryptoctx,
5319                       int *cert_count)
5320 {
5321     int count;
5322 
5323     if (id_cryptoctx == NULL || id_cryptoctx->creds[0] == NULL)
5324         return EINVAL;
5325 
5326     for (count = 0;
5327          count <= MAX_CREDS_ALLOWED && id_cryptoctx->creds[count] != NULL;
5328          count++);
5329     *cert_count = count;
5330     return 0;
5331 }
5332 
5333 
5334 /*
5335  * Begin iteration over the certs loaded in crypto_load_certs()
5336  */
5337 /* ARGSUSED */
5338 krb5_error_code
5339 crypto_cert_iteration_begin(krb5_context context,
5340                             pkinit_plg_crypto_context plg_cryptoctx,
5341                             pkinit_req_crypto_context req_cryptoctx,
5342                             pkinit_identity_crypto_context id_cryptoctx,
5343                             pkinit_cert_iter_handle *ih_ret)
5344 {
5345     struct _pkinit_cert_iter_data *id;
5346 
5347     if (id_cryptoctx == NULL || ih_ret == NULL)
5348         return EINVAL;
5349     if (id_cryptoctx->creds[0] == NULL)      /* No cred info available */
5350         return ENOENT;
5351 
5352     id = calloc(1, sizeof(*id));
5353     if (id == NULL)
5354         return ENOMEM;
5355     id->magic = ITER_MAGIC;
5356     id->plgctx = plg_cryptoctx,
5357     id->reqctx = req_cryptoctx,
5358     id->idctx = id_cryptoctx;
5359     id->index = 0;
5360     *ih_ret = (pkinit_cert_iter_handle) id;
5361     return 0;
5362 }
5363 
5364 /*
5365  * End iteration over the certs loaded in crypto_load_certs()
5366  */
5367 /* ARGSUSED */
5368 krb5_error_code
5369 crypto_cert_iteration_end(krb5_context context,
5370                           pkinit_cert_iter_handle ih)
5371 {
5372     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5373 
5374     if (id == NULL || id->magic != ITER_MAGIC)
5375         return EINVAL;
5376     free(ih);
5377     return 0;
5378 }
5379 
5380 /*
5381  * Get next certificate handle
5382  */
5383 /* ARGSUSED */
5384 krb5_error_code
5385 crypto_cert_iteration_next(krb5_context context,
5386                            pkinit_cert_iter_handle ih,
5387                            pkinit_cert_handle *ch_ret)
5388 {
5389     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5390     struct _pkinit_cert_data *cd;
5391     pkinit_identity_crypto_context id_cryptoctx;
5392 
5393     if (id == NULL || id->magic != ITER_MAGIC)
5394         return EINVAL;
5395 
5396     if (ch_ret == NULL)
5397         return EINVAL;
5398 
5399     id_cryptoctx = id->idctx;
5400     if (id_cryptoctx == NULL)
5401         return EINVAL;
5402 
5403     if (id_cryptoctx->creds[id->index] == NULL)
5404         return PKINIT_ITER_NO_MORE;
5405     
5406     cd = calloc(1, sizeof(*cd));
5407     if (cd == NULL)
5408         return ENOMEM;
5409 
5410     cd->magic = CERT_MAGIC;
5411     cd->plgctx = id->plgctx;
5412     cd->reqctx = id->reqctx;
5413     cd->idctx = id->idctx;
5414     cd->index = id->index;
5415     cd->cred = id_cryptoctx->creds[id->index++];
5416     *ch_ret = (pkinit_cert_handle)cd;
5417     return 0;
5418 }
5419 
5420 /*
5421  * Release cert handle
5422  */
5423 /* ARGSUSED */
5424 krb5_error_code
5425 crypto_cert_release(krb5_context context,
5426                     pkinit_cert_handle ch)
5427 {
5428     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5429     if (cd == NULL || cd->magic != CERT_MAGIC)
5430         return EINVAL;
5431     free(cd);
5432     return 0;
5433 }
5434 
5435 /*
5436  * Get certificate Key Usage and Extended Key Usage
5437  */
5438 /* ARGSUSED */
5439 static krb5_error_code
5440 crypto_retieve_X509_key_usage(krb5_context context,
5441                               pkinit_plg_crypto_context plgcctx,
5442                               pkinit_req_crypto_context reqcctx,
5443                               X509 *x,
5444                               unsigned int *ret_ku_bits,
5445                               unsigned int *ret_eku_bits)
5446 {
5447     /* Solaris Kerberos */
5448     int i;
5449     unsigned int eku_bits = 0, ku_bits = 0;
5450     ASN1_BIT_STRING *usage = NULL;
5451 
5452     if (ret_ku_bits == NULL && ret_eku_bits == NULL)
5453         return EINVAL;
5454 
5455     if (ret_eku_bits)
5456         *ret_eku_bits = 0;
5457     else {
5458         pkiDebug("%s: EKUs not requested, not checking\n", __FUNCTION__);
5459         goto check_kus;
5460     }
5461     
5462     /* Start with Extended Key usage */
5463     i = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
5464     if (i >= 0) {
5465         EXTENDED_KEY_USAGE *eku;
5466 
5467         eku = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL);
5468         if (eku) {
5469             for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
5470                 ASN1_OBJECT *certoid;
5471                 certoid = sk_ASN1_OBJECT_value(eku, i);
5472                 if ((OBJ_cmp(certoid, plgcctx->id_pkinit_KPClientAuth)) == 0)
5473                     eku_bits |= PKINIT_EKU_PKINIT;
5474                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_ms_smartcard_login))) == 0)
5475                     eku_bits |= PKINIT_EKU_MSSCLOGIN;
5476                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_client_auth))) == 0)
5477                     eku_bits |= PKINIT_EKU_CLIENTAUTH;
5478                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_email_protect))) == 0)
5479                     eku_bits |= PKINIT_EKU_EMAILPROTECTION;
5480             }
5481             EXTENDED_KEY_USAGE_free(eku);
5482         }
5483     }
5484     pkiDebug("%s: returning eku 0x%08x\n", __FUNCTION__, eku_bits);
5485     *ret_eku_bits = eku_bits;
5486 
5487 check_kus:
5488     /* Now the Key Usage bits */
5489     if (ret_ku_bits)
5490         *ret_ku_bits = 0;
5491     else {
5492         pkiDebug("%s: KUs not requested, not checking\n", __FUNCTION__);
5493         goto out;
5494     }
5495 
5496     /* Make sure usage exists before checking bits */
5497     usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL);
5498     if (usage) {
5499         if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
5500             ku_bits |= PKINIT_KU_DIGITALSIGNATURE;
5501         if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
5502             ku_bits |= PKINIT_KU_KEYENCIPHERMENT;
5503         ASN1_BIT_STRING_free(usage);
5504     }
5505 
5506     pkiDebug("%s: returning ku 0x%08x\n", __FUNCTION__, ku_bits);
5507     *ret_ku_bits = ku_bits;
5508 
5509 out:
5510     return 0;
5511 }
5512 
5513 /*
5514  * Return a string format of an X509_NAME in buf where
5515  * size is an in/out parameter.  On input it is the size
5516  * of the buffer, and on output it is the actual length
5517  * of the name.
5518  * If buf is NULL, returns the length req'd to hold name
5519  */
5520 static char *
5521 X509_NAME_oneline_ex(X509_NAME * a,
5522                      char *buf,
5523                      unsigned int *size,
5524                      unsigned long flag)
5525 {
5526   BIO *out = NULL;
5527 
5528   out = BIO_new(BIO_s_mem ());
5529   if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
5530     if (buf != NULL && *size > (int) BIO_number_written(out)) {
5531       (void) memset(buf, 0, *size);
5532       BIO_read(out, buf, (int) BIO_number_written(out));
5533     }
5534     else {
5535       *size = BIO_number_written(out);
5536     }
5537   }
5538   BIO_free(out);
5539   return (buf);
5540 }
5541 
5542 /*
5543  * Get certificate information
5544  */
5545 krb5_error_code
5546 crypto_cert_get_matching_data(krb5_context context,
5547                               pkinit_cert_handle ch,
5548                               pkinit_cert_matching_data **ret_md)
5549 {
5550     krb5_error_code retval;
5551     pkinit_cert_matching_data *md;
5552     krb5_principal *pkinit_sans =NULL, *upn_sans = NULL;
5553     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5554     int i, j;
5555     char buf[DN_BUF_LEN];
5556     unsigned int bufsize = sizeof(buf);
5557 
5558     if (cd == NULL || cd->magic != CERT_MAGIC)
5559         return EINVAL;
5560     if (ret_md == NULL)
5561         return EINVAL;
5562 
5563     md = calloc(1, sizeof(*md));
5564     if (md == NULL)
5565         return ENOMEM;
5566 
5567     md->ch = ch;
5568 
5569     /* get the subject name (in rfc2253 format) */
5570     X509_NAME_oneline_ex(X509_get_subject_name(cd->cred->cert),
5571                          buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5572     md->subject_dn = strdup(buf);
5573     if (md->subject_dn == NULL) {
5574         retval = ENOMEM;
5575         goto cleanup;
5576     }
5577 
5578     /* get the issuer name (in rfc2253 format) */
5579     X509_NAME_oneline_ex(X509_get_issuer_name(cd->cred->cert),
5580                          buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5581     md->issuer_dn = strdup(buf);
5582     if (md->issuer_dn == NULL) {
5583         retval = ENOMEM;
5584         goto cleanup;
5585     }
5586 
5587     /* get the san data */
5588     retval = crypto_retrieve_X509_sans(context, cd->plgctx, cd->reqctx,
5589                                        cd->cred->cert, &pkinit_sans,
5590                                        &upn_sans, NULL);
5591     if (retval)
5592         goto cleanup;
5593 
5594     j = 0;
5595     if (pkinit_sans != NULL) {
5596         for (i = 0; pkinit_sans[i] != NULL; i++)
5597             j++;
5598     }
5599     if (upn_sans != NULL) {
5600         for (i = 0; upn_sans[i] != NULL; i++)
5601             j++;
5602     }
5603     if (j != 0) {
5604         md->sans = calloc((size_t)j+1, sizeof(*md->sans));
5605         if (md->sans == NULL) {
5606             retval = ENOMEM;
5607             goto cleanup;
5608         }
5609         j = 0;
5610         if (pkinit_sans != NULL) {
5611             for (i = 0; pkinit_sans[i] != NULL; i++)
5612                 md->sans[j++] = pkinit_sans[i];
5613             free(pkinit_sans);
5614         }
5615         if (upn_sans != NULL) {
5616             for (i = 0; upn_sans[i] != NULL; i++)
5617                 md->sans[j++] = upn_sans[i];
5618             free(upn_sans);
5619         }
5620         md->sans[j] = NULL;
5621     } else
5622         md->sans = NULL;
5623 
5624     /* get the KU and EKU data */
5625 
5626     retval = crypto_retieve_X509_key_usage(context, cd->plgctx, cd->reqctx,
5627                                            cd->cred->cert,
5628                                            &md->ku_bits, &md->eku_bits);
5629     if (retval)
5630         goto cleanup;
5631 
5632     *ret_md = md;
5633     retval = 0;
5634 cleanup:
5635     if (retval) {
5636         if (md)
5637             crypto_cert_free_matching_data(context, md);
5638     }
5639     return retval;
5640 }
5641 
5642 /*
5643  * Free certificate information
5644  */
5645 krb5_error_code
5646 crypto_cert_free_matching_data(krb5_context context,
5647                       pkinit_cert_matching_data *md)
5648 {
5649     krb5_principal p;
5650     int i;
5651 
5652     if (md == NULL)
5653         return EINVAL;
5654     if (md->subject_dn)
5655         free(md->subject_dn);
5656     if (md->issuer_dn)
5657         free(md->issuer_dn);
5658     if (md->sans) {
5659         for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i])
5660             krb5_free_principal(context, p);
5661         free(md->sans);
5662     }
5663     free(md);
5664     return 0;
5665 }
5666 
5667 /*
5668  * Make this matching certificate "the chosen one"
5669  */
5670 /* ARGSUSED */
5671 krb5_error_code
5672 crypto_cert_select(krb5_context context,
5673                    pkinit_cert_matching_data *md)
5674 {
5675     struct _pkinit_cert_data *cd;
5676     if (md == NULL)
5677         return EINVAL;
5678 
5679     cd = (struct _pkinit_cert_data *)md->ch;
5680     if (cd == NULL || cd->magic != CERT_MAGIC)
5681         return EINVAL;
5682     
5683     /* copy the selected cert into our id_cryptoctx */ 
5684     if (cd->idctx->my_certs != NULL) {
5685         sk_X509_pop_free(cd->idctx->my_certs, X509_free);
5686     }
5687     cd->idctx->my_certs = sk_X509_new_null();     
5688     sk_X509_push(cd->idctx->my_certs, cd->cred->cert);
5689     cd->idctx->creds[cd->index]->cert = NULL;           /* Don't free it twice */
5690     cd->idctx->cert_index = 0;
5691 
5692     if (cd->idctx->pkcs11_method != 1) {
5693         cd->idctx->my_key = cd->cred->key;
5694         cd->idctx->creds[cd->index]->key = NULL;    /* Don't free it twice */
5695     } 
5696 #ifndef WITHOUT_PKCS11
5697     else {
5698         cd->idctx->cert_id = cd->cred->cert_id;
5699         cd->idctx->creds[cd->index]->cert_id = NULL; /* Don't free it twice */
5700         cd->idctx->cert_id_len = cd->cred->cert_id_len;
5701     }
5702 #endif
5703     return 0;
5704 }
5705 
5706 /*
5707  * Choose the default certificate as "the chosen one"
5708  */
5709 krb5_error_code
5710 crypto_cert_select_default(krb5_context context,
5711                            pkinit_plg_crypto_context plg_cryptoctx,
5712                            pkinit_req_crypto_context req_cryptoctx,
5713                            pkinit_identity_crypto_context id_cryptoctx)
5714 {
5715     krb5_error_code retval;
5716     int cert_count = 0;
5717 
5718     retval = crypto_cert_get_count(context, plg_cryptoctx, req_cryptoctx,
5719                                    id_cryptoctx, &cert_count);
5720     if (retval) {
5721         pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
5722                  __FUNCTION__, retval, error_message(retval));
5723         goto errout;
5724     }
5725     if (cert_count != 1) {
5726         /* Solaris Kerberos: Improved error messages */
5727         retval = EINVAL;
5728         krb5_set_error_message(context, retval,
5729             gettext("Failed to select default certificate: "
5730                 "found %d certs to choose from but there must be exactly one"),
5731             cert_count);
5732         pkiDebug("%s: ERROR: There are %d certs to choose from, "
5733                  "but there must be exactly one.\n",
5734                  __FUNCTION__, cert_count);
5735         goto errout;
5736     }
5737     /* copy the selected cert into our id_cryptoctx */ 
5738     if (id_cryptoctx->my_certs != NULL) {
5739         sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
5740     }
5741     id_cryptoctx->my_certs = sk_X509_new_null();     
5742     sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
5743     id_cryptoctx->creds[0]->cert = NULL;  /* Don't free it twice */
5744     id_cryptoctx->cert_index = 0;
5745 
5746     if (id_cryptoctx->pkcs11_method != 1) {
5747         id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
5748         id_cryptoctx->creds[0]->key = NULL;       /* Don't free it twice */
5749     } 
5750 #ifndef WITHOUT_PKCS11
5751     else {
5752         id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
5753         id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
5754         id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
5755     }
5756 #endif
5757     retval = 0;
5758 errout:
5759     return retval;
5760 }
5761 
5762 
5763 /* ARGSUSED */
5764 static krb5_error_code
5765 load_cas_and_crls(krb5_context context,
5766                   pkinit_plg_crypto_context plg_cryptoctx,
5767                   pkinit_req_crypto_context req_cryptoctx,
5768                   pkinit_identity_crypto_context id_cryptoctx,
5769                   int catype,
5770                   char *filename)
5771 {
5772     STACK_OF(X509_INFO) *sk = NULL;
5773     STACK_OF(X509) *ca_certs = NULL;
5774     STACK_OF(X509_CRL) *ca_crls = NULL;
5775     BIO *in = NULL;
5776     /* Solaris Kerberos */
5777     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
5778     int i = 0;
5779 
5780     /* If there isn't already a stack in the context,
5781      * create a temporary one now */
5782     switch(catype) {
5783     case CATYPE_ANCHORS:
5784         if (id_cryptoctx->trustedCAs != NULL)
5785             ca_certs = id_cryptoctx->trustedCAs;
5786         else {
5787             ca_certs = sk_X509_new_null();
5788             if (ca_certs == NULL)
5789                 return ENOMEM;
5790         }
5791         break;
5792     case CATYPE_INTERMEDIATES:
5793         if (id_cryptoctx->intermediateCAs != NULL)
5794             ca_certs = id_cryptoctx->intermediateCAs;
5795         else {
5796             ca_certs = sk_X509_new_null();
5797             if (ca_certs == NULL)
5798                 return ENOMEM;
5799         }
5800         break;
5801     case CATYPE_CRLS:
5802         if (id_cryptoctx->revoked != NULL)
5803             ca_crls = id_cryptoctx->revoked;
5804         else {
5805             ca_crls = sk_X509_CRL_new_null();
5806             if (ca_crls == NULL)
5807                 return ENOMEM;
5808         }
5809         break;
5810     default:
5811         return ENOTSUP;
5812     }
5813 
5814     if (!(in = BIO_new_file(filename, "r"))) {
5815         retval = errno;
5816         pkiDebug("%s: error opening file '%s': %s\n", __FUNCTION__,
5817                  filename, error_message(errno));
5818         goto cleanup;
5819     }
5820 
5821     /* This loads from a file, a stack of x509/crl/pkey sets */
5822     if ((sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) {
5823         pkiDebug("%s: error reading file '%s'\n", __FUNCTION__, filename);
5824         retval = EIO;
5825         goto cleanup;
5826     }
5827 
5828     /* scan over the stack created from loading the file contents,
5829      * weed out duplicates, and push new ones onto the return stack
5830      */
5831     for (i = 0; i < sk_X509_INFO_num(sk); i++) {
5832         X509_INFO *xi = sk_X509_INFO_value(sk, i);
5833         if (xi != NULL && xi->x509 != NULL && catype != CATYPE_CRLS) { 
5834             int j = 0, size = sk_X509_num(ca_certs), flag = 0;
5835 
5836             if (!size) {
5837                 sk_X509_push(ca_certs, xi->x509);
5838                 xi->x509 = NULL;
5839                 continue;
5840             }
5841             for (j = 0; j < size; j++) {
5842                 X509 *x = sk_X509_value(ca_certs, j);
5843                 flag = X509_cmp(x, xi->x509);
5844                 if (flag == 0)
5845                     break;
5846                 else 
5847                     continue;
5848             }
5849             if (flag != 0) {
5850                 sk_X509_push(ca_certs, X509_dup(xi->x509));
5851             }
5852         } else if (xi != NULL && xi->crl != NULL && catype == CATYPE_CRLS) {
5853             int j = 0, size = sk_X509_CRL_num(ca_crls), flag = 0;
5854             if (!size) {
5855                 sk_X509_CRL_push(ca_crls, xi->crl);
5856                 xi->crl = NULL;
5857                 continue;
5858             }
5859             for (j = 0; j < size; j++) {
5860                 X509_CRL *x = sk_X509_CRL_value(ca_crls, j);
5861                 flag = X509_CRL_cmp(x, xi->crl);
5862                 if (flag == 0)
5863                     break;
5864                 else
5865                     continue;
5866             }
5867             if (flag != 0) {
5868                 sk_X509_CRL_push(ca_crls, X509_CRL_dup(xi->crl));
5869             }
5870         }
5871     }
5872 
5873     /* If we added something and there wasn't a stack in the
5874      * context before, add the temporary stack to the context.
5875      */
5876     switch(catype) {
5877     case CATYPE_ANCHORS:
5878         if (sk_X509_num(ca_certs) == 0) {
5879             pkiDebug("no anchors in file, %s\n", filename);
5880             if (id_cryptoctx->trustedCAs == NULL) 
5881                 sk_X509_free(ca_certs);
5882         } else {
5883             if (id_cryptoctx->trustedCAs == NULL)
5884                 id_cryptoctx->trustedCAs = ca_certs;
5885         }
5886         break;
5887     case CATYPE_INTERMEDIATES:
5888         if (sk_X509_num(ca_certs) == 0) {
5889             pkiDebug("no intermediates in file, %s\n", filename);
5890             if (id_cryptoctx->intermediateCAs == NULL) 
5891                 sk_X509_free(ca_certs);
5892         } else {
5893             if (id_cryptoctx->intermediateCAs == NULL)
5894                 id_cryptoctx->intermediateCAs = ca_certs;
5895         }
5896         break;
5897     case CATYPE_CRLS:
5898         if (sk_X509_CRL_num(ca_crls) == 0) {
5899             pkiDebug("no crls in file, %s\n", filename);
5900             if (id_cryptoctx->revoked == NULL)
5901                 sk_X509_CRL_free(ca_crls);
5902         } else {
5903             if (id_cryptoctx->revoked == NULL)
5904                 id_cryptoctx->revoked = ca_crls;
5905         }
5906         break;
5907     default:
5908         /* Should have been caught above! */
5909         retval = EINVAL;
5910         goto cleanup;
5911         /* Solaris Kerberos: removed "break" as it's never reached */
5912     }
5913 
5914     retval = 0;
5915 
5916   cleanup:
5917     if (in != NULL)
5918         BIO_free(in);
5919     if (sk != NULL)
5920         sk_X509_INFO_pop_free(sk, X509_INFO_free);
5921 
5922     return retval;
5923 }
5924 
5925 static krb5_error_code
5926 load_cas_and_crls_dir(krb5_context context,
5927                       pkinit_plg_crypto_context plg_cryptoctx,
5928                       pkinit_req_crypto_context req_cryptoctx,
5929                       pkinit_identity_crypto_context id_cryptoctx,
5930                       int catype,
5931                       char *dirname) 
5932 {
5933     krb5_error_code retval = EINVAL;
5934     DIR *d = NULL;
5935     struct dirent *dentry = NULL;
5936     char filename[1024];
5937 
5938     if (dirname == NULL)
5939         return EINVAL;
5940 
5941     d = opendir(dirname);
5942     if (d == NULL) 
5943         return ENOENT;
5944 
5945     while ((dentry = readdir(d))) {
5946         if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(filename)) {
5947             pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5948                      __FUNCTION__, dirname, dentry->d_name);
5949             goto cleanup;
5950         }
5951         /* Ignore subdirectories and anything starting with a dot */
5952 #ifdef DT_DIR
5953         if (dentry->d_type == DT_DIR)
5954             continue;
5955 #endif
5956         if (dentry->d_name[0] == '.')
5957             continue;
5958         (void) snprintf(filename, sizeof(filename), "%s/%s", dirname, dentry->d_name);
5959 
5960         retval = load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
5961                                    id_cryptoctx, catype, filename);
5962         if (retval)
5963             goto cleanup;
5964     }
5965 
5966     retval = 0;
5967 
5968   cleanup:
5969     if (d != NULL) 
5970         (void) closedir(d);
5971 
5972     return retval;
5973 }
5974 
5975 /* ARGSUSED */
5976 krb5_error_code
5977 crypto_load_cas_and_crls(krb5_context context,
5978                          pkinit_plg_crypto_context plg_cryptoctx,
5979                          pkinit_req_crypto_context req_cryptoctx,
5980                          pkinit_identity_opts *idopts,
5981                          pkinit_identity_crypto_context id_cryptoctx,
5982                          int idtype,
5983                          int catype,
5984                          char *id) 
5985 {
5986     pkiDebug("%s: called with idtype %s and catype %s\n",
5987              __FUNCTION__, idtype2string(idtype), catype2string(catype));
5988     /* Solaris Kerberos: Removed "break"'s as they are never reached */
5989     switch (idtype) {
5990     case IDTYPE_FILE:
5991         return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
5992                                  id_cryptoctx, catype, id);
5993     case IDTYPE_DIR:
5994         return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
5995                                      id_cryptoctx, catype, id);
5996     default:
5997         return ENOTSUP;
5998     }
5999 }
6000 
6001 static krb5_error_code
6002 create_identifiers_from_stack(STACK_OF(X509) *sk,
6003                               krb5_external_principal_identifier *** ids)
6004 {
6005     krb5_error_code retval = ENOMEM;
6006     int i = 0, sk_size = sk_X509_num(sk);
6007     krb5_external_principal_identifier **krb5_cas = NULL;
6008     X509 *x = NULL;
6009     X509_NAME *xn = NULL;
6010     unsigned char *p = NULL;
6011     int len = 0;
6012     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6013     char buf[DN_BUF_LEN];
6014 
6015     *ids = NULL;
6016 
6017     krb5_cas =
6018         malloc((sk_size + 1) * sizeof(krb5_external_principal_identifier *));
6019     if (krb5_cas == NULL)
6020         return ENOMEM;
6021     krb5_cas[sk_size] = NULL;
6022 
6023     for (i = 0; i < sk_size; i++) {
6024         krb5_cas[i] = (krb5_external_principal_identifier *)malloc(sizeof(krb5_external_principal_identifier));
6025 
6026         x = sk_X509_value(sk, i);
6027 
6028         X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6029         pkiDebug("#%d cert= %s\n", i, buf);
6030 
6031         /* fill-in subjectName */
6032         krb5_cas[i]->subjectName.magic = 0;
6033         krb5_cas[i]->subjectName.length = 0;
6034         krb5_cas[i]->subjectName.data = NULL;
6035 
6036         xn = X509_get_subject_name(x);
6037         len = i2d_X509_NAME(xn, NULL);
6038         if ((p = krb5_cas[i]->subjectName.data = (unsigned char *)malloc((size_t) len)) == NULL)
6039             goto cleanup;
6040         i2d_X509_NAME(xn, &p);
6041         krb5_cas[i]->subjectName.length = len;
6042 
6043         /* fill-in issuerAndSerialNumber */
6044         krb5_cas[i]->issuerAndSerialNumber.length = 0;
6045         krb5_cas[i]->issuerAndSerialNumber.magic = 0;
6046         krb5_cas[i]->issuerAndSerialNumber.data = NULL;
6047 
6048 #ifdef LONGHORN_BETA_COMPAT
6049 if (longhorn == 0) { /* XXX Longhorn doesn't like this */
6050 #endif
6051         is = PKCS7_ISSUER_AND_SERIAL_new();
6052         X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6053         M_ASN1_INTEGER_free(is->serial);
6054         is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
6055         len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6056         if ((p = krb5_cas[i]->issuerAndSerialNumber.data =
6057              (unsigned char *)malloc((size_t) len)) == NULL)
6058             goto cleanup;
6059         i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6060         krb5_cas[i]->issuerAndSerialNumber.length = len;
6061 #ifdef LONGHORN_BETA_COMPAT
6062 }
6063 #endif
6064 
6065         /* fill-in subjectKeyIdentifier */
6066         krb5_cas[i]->subjectKeyIdentifier.length = 0;
6067         krb5_cas[i]->subjectKeyIdentifier.magic = 0;
6068         krb5_cas[i]->subjectKeyIdentifier.data = NULL;
6069 
6070 
6071 #ifdef LONGHORN_BETA_COMPAT
6072 if (longhorn == 0) {    /* XXX Longhorn doesn't like this */
6073 #endif
6074         if (X509_get_ext_by_NID(x, NID_subject_key_identifier, -1) >= 0) {
6075             ASN1_OCTET_STRING *ikeyid = NULL;
6076 
6077             if ((ikeyid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL,
6078                                            NULL))) {
6079                 len = i2d_ASN1_OCTET_STRING(ikeyid, NULL);
6080                 if ((p = krb5_cas[i]->subjectKeyIdentifier.data =
6081                         (unsigned char *)malloc((size_t) len)) == NULL)
6082                     goto cleanup;
6083                 i2d_ASN1_OCTET_STRING(ikeyid, &p);          
6084                 krb5_cas[i]->subjectKeyIdentifier.length = len;
6085             }
6086             if (ikeyid != NULL)
6087                 ASN1_OCTET_STRING_free(ikeyid);
6088         }
6089 #ifdef LONGHORN_BETA_COMPAT
6090 }
6091 #endif
6092         if (is != NULL) {
6093             if (is->issuer != NULL)
6094                 X509_NAME_free(is->issuer);
6095             if (is->serial != NULL)
6096                 ASN1_INTEGER_free(is->serial);
6097             free(is);
6098         }
6099     }
6100 
6101     *ids = krb5_cas;
6102 
6103     retval = 0;
6104   cleanup:
6105     if (retval)
6106         free_krb5_external_principal_identifier(&krb5_cas);
6107 
6108     return retval;
6109 }
6110 
6111 /* ARGSUSED */
6112 static krb5_error_code
6113 create_krb5_invalidCertificates(krb5_context context,
6114                                 pkinit_plg_crypto_context plg_cryptoctx,
6115                                 pkinit_req_crypto_context req_cryptoctx,
6116                                 pkinit_identity_crypto_context id_cryptoctx,
6117                                 krb5_external_principal_identifier *** ids)
6118 {
6119 
6120     krb5_error_code retval = ENOMEM;
6121     STACK_OF(X509) *sk = NULL;
6122 
6123     *ids = NULL;
6124     if (req_cryptoctx->received_cert == NULL)
6125         return KRB5KDC_ERR_PREAUTH_FAILED;
6126 
6127     sk = sk_X509_new_null();
6128     if (sk == NULL) 
6129         goto cleanup;
6130     sk_X509_push(sk, req_cryptoctx->received_cert);
6131 
6132     retval = create_identifiers_from_stack(sk, ids);
6133 
6134     sk_X509_free(sk);
6135 cleanup:
6136 
6137     return retval;
6138 }
6139 
6140 /* ARGSUSED */
6141 krb5_error_code
6142 create_krb5_supportedCMSTypes(krb5_context context,
6143                               pkinit_plg_crypto_context plg_cryptoctx,
6144                               pkinit_req_crypto_context req_cryptoctx,
6145                               pkinit_identity_crypto_context id_cryptoctx,
6146                               krb5_algorithm_identifier ***oids)
6147 {
6148 
6149     krb5_error_code retval = ENOMEM;
6150     krb5_algorithm_identifier **loids = NULL;
6151     krb5_octet_data des3oid = {0, 8, (unsigned char *)"\x2A\x86\x48\x86\xF7\x0D\x03\x07" };
6152 
6153     *oids = NULL;
6154     loids = malloc(2 * sizeof(krb5_algorithm_identifier *));
6155     if (loids == NULL)
6156         goto cleanup;
6157     loids[1] = NULL;
6158     loids[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
6159     if (loids[0] == NULL) {
6160         free(loids);
6161         goto cleanup;
6162     }
6163     retval = pkinit_copy_krb5_octet_data(&loids[0]->algorithm, &des3oid);
6164     if (retval) {
6165         free(loids[0]);
6166         free(loids);
6167         goto cleanup;
6168     }
6169     loids[0]->parameters.length = 0;
6170     loids[0]->parameters.data = NULL;
6171 
6172     *oids = loids;
6173     retval = 0;
6174 cleanup:
6175 
6176     return retval;
6177 }
6178 
6179 /* ARGSUSED */
6180 krb5_error_code
6181 create_krb5_trustedCertifiers(krb5_context context,
6182                               pkinit_plg_crypto_context plg_cryptoctx,
6183                               pkinit_req_crypto_context req_cryptoctx,
6184                               pkinit_identity_crypto_context id_cryptoctx,
6185                               krb5_external_principal_identifier *** ids)
6186 {
6187 
6188     /* Solaris Kerberos */
6189     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6190 
6191     *ids = NULL;
6192     if (id_cryptoctx->trustedCAs == NULL)
6193         return KRB5KDC_ERR_PREAUTH_FAILED;
6194 
6195     return create_identifiers_from_stack(sk, ids);
6196     
6197 }
6198 
6199 /* ARGSUSED */
6200 krb5_error_code
6201 create_krb5_trustedCas(krb5_context context,
6202                        pkinit_plg_crypto_context plg_cryptoctx,
6203                        pkinit_req_crypto_context req_cryptoctx,
6204                        pkinit_identity_crypto_context id_cryptoctx,
6205                        int flag,
6206                        krb5_trusted_ca *** ids)
6207 {
6208     krb5_error_code retval = ENOMEM;
6209     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6210     int i = 0, len = 0, sk_size = sk_X509_num(sk);
6211     krb5_trusted_ca **krb5_cas = NULL;
6212     X509 *x = NULL;
6213     char buf[DN_BUF_LEN];
6214     X509_NAME *xn = NULL;
6215     unsigned char *p = NULL;
6216     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6217 
6218     *ids = NULL;
6219     if (id_cryptoctx->trustedCAs == NULL)
6220         return KRB5KDC_ERR_PREAUTH_FAILED;
6221 
6222     krb5_cas = malloc((sk_size + 1) * sizeof(krb5_trusted_ca *));
6223     if (krb5_cas == NULL)
6224         return ENOMEM;
6225     krb5_cas[sk_size] = NULL;
6226 
6227     for (i = 0; i < sk_size; i++) {
6228         krb5_cas[i] = (krb5_trusted_ca *)malloc(sizeof(krb5_trusted_ca));
6229         if (krb5_cas[i] == NULL)
6230             goto cleanup;
6231         x = sk_X509_value(sk, i);
6232 
6233         X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6234         pkiDebug("#%d cert= %s\n", i, buf);
6235 
6236         switch (flag) {
6237             case choice_trusted_cas_principalName:
6238                 krb5_cas[i]->choice = choice_trusted_cas_principalName;
6239                 break;
6240             case choice_trusted_cas_caName:
6241                 krb5_cas[i]->choice = choice_trusted_cas_caName;
6242                 krb5_cas[i]->u.caName.data = NULL;
6243                 krb5_cas[i]->u.caName.length = 0;
6244                 xn = X509_get_subject_name(x);
6245                 len = i2d_X509_NAME(xn, NULL);
6246                 if ((p = krb5_cas[i]->u.caName.data =
6247                     (unsigned char *)malloc((size_t) len)) == NULL)
6248                     goto cleanup;
6249                 i2d_X509_NAME(xn, &p);
6250                 krb5_cas[i]->u.caName.length = len;
6251                 break;
6252             case choice_trusted_cas_issuerAndSerial:
6253                 krb5_cas[i]->choice = choice_trusted_cas_issuerAndSerial;
6254                 krb5_cas[i]->u.issuerAndSerial.data = NULL;
6255                 krb5_cas[i]->u.issuerAndSerial.length = 0;
6256                 is = PKCS7_ISSUER_AND_SERIAL_new();
6257                 X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6258                 M_ASN1_INTEGER_free(is->serial);
6259                 is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
6260                 len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6261                 if ((p = krb5_cas[i]->u.issuerAndSerial.data =
6262                     (unsigned char *)malloc((size_t) len)) == NULL)
6263                     goto cleanup;
6264                 i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6265                 krb5_cas[i]->u.issuerAndSerial.length = len;
6266                 if (is != NULL) {
6267                     if (is->issuer != NULL)
6268                         X509_NAME_free(is->issuer);
6269                     if (is->serial != NULL)
6270                         ASN1_INTEGER_free(is->serial);
6271                     free(is);
6272                 }
6273                 break;
6274             default: break;
6275         }
6276     }
6277     retval = 0;
6278     *ids = krb5_cas;
6279 cleanup:
6280     if (retval)
6281         free_krb5_trusted_ca(&krb5_cas);
6282 
6283     return retval;
6284 }
6285 
6286 /* ARGSUSED */
6287 krb5_error_code
6288 create_issuerAndSerial(krb5_context context,
6289                        pkinit_plg_crypto_context plg_cryptoctx,
6290                        pkinit_req_crypto_context req_cryptoctx,
6291                        pkinit_identity_crypto_context id_cryptoctx,
6292                        unsigned char **out,
6293                        unsigned int *out_len)
6294 {
6295     unsigned char *p = NULL;
6296     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6297     int len = 0;
6298     krb5_error_code retval = ENOMEM;
6299     X509 *cert = req_cryptoctx->received_cert;
6300 
6301     *out = NULL;
6302     *out_len = 0;
6303     if (req_cryptoctx->received_cert == NULL)
6304         return 0;
6305 
6306     is = PKCS7_ISSUER_AND_SERIAL_new();
6307     X509_NAME_set(&is->issuer, X509_get_issuer_name(cert));
6308     M_ASN1_INTEGER_free(is->serial);
6309     is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(cert));
6310     len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6311     if ((p = *out = (unsigned char *)malloc((size_t) len)) == NULL)
6312         goto cleanup;
6313     i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6314     *out_len = len;
6315     retval = 0;
6316 
6317 cleanup:
6318     X509_NAME_free(is->issuer);
6319     ASN1_INTEGER_free(is->serial);
6320     free(is);
6321 
6322     return retval;
6323 }
6324 
6325 static int
6326 pkcs7_decrypt(krb5_context context,
6327               pkinit_identity_crypto_context id_cryptoctx,
6328               PKCS7 *p7,
6329               BIO *data)
6330 {
6331     BIO *tmpmem = NULL;
6332     /* Solaris Kerberos */
6333     int i = 0;
6334     char buf[4096];
6335 
6336     if(p7 == NULL)
6337         return 0;
6338 
6339     if(!PKCS7_type_is_enveloped(p7)) {
6340         pkiDebug("wrong pkcs7 content type\n");
6341         return 0;
6342     }
6343 
6344     if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) {
6345         pkiDebug("unable to decrypt pkcs7 object\n");
6346         return 0;
6347     }
6348 /* Solaris Kerberos: Suppress sun studio compiler warning */
6349 #pragma error_messages (off, E_END_OF_LOOP_CODE_NOT_REACHED)
6350     for(;;) {
6351         i = BIO_read(tmpmem, buf, sizeof(buf));
6352         if (i <= 0) break;
6353         BIO_write(data, buf, i);
6354         BIO_free_all(tmpmem);
6355         return 1;
6356     }
6357 #pragma error_messages (default, E_END_OF_LOOP_CODE_NOT_REACHED)
6358 
6359     return 0; 
6360 }
6361 
6362 krb5_error_code
6363 pkinit_process_td_trusted_certifiers(
6364     krb5_context context,
6365     pkinit_plg_crypto_context plg_cryptoctx,
6366     pkinit_req_crypto_context req_cryptoctx,
6367     pkinit_identity_crypto_context id_cryptoctx,
6368     krb5_external_principal_identifier **krb5_trusted_certifiers,
6369     int td_type)
6370 {
6371     krb5_error_code retval = ENOMEM;
6372     STACK_OF(X509_NAME) *sk_xn = NULL;
6373     X509_NAME *xn = NULL;
6374     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6375     ASN1_OCTET_STRING *id = NULL;
6376     const unsigned char *p = NULL;
6377     char buf[DN_BUF_LEN];
6378     int i = 0;
6379 
6380     if (td_type == TD_TRUSTED_CERTIFIERS)
6381         pkiDebug("received trusted certifiers\n");
6382     else
6383         pkiDebug("received invalid certificate\n");
6384 
6385     sk_xn = sk_X509_NAME_new_null();
6386     while(krb5_trusted_certifiers[i] != NULL) {
6387         if (krb5_trusted_certifiers[i]->subjectName.data != NULL) {
6388             p = krb5_trusted_certifiers[i]->subjectName.data;
6389             xn = d2i_X509_NAME(NULL, &p,
6390                 (int)krb5_trusted_certifiers[i]->subjectName.length);
6391             if (xn == NULL)
6392                 goto cleanup;
6393             X509_NAME_oneline(xn, buf, sizeof(buf));
6394             if (td_type == TD_TRUSTED_CERTIFIERS)
6395                 pkiDebug("#%d cert = %s is trusted by kdc\n", i, buf);
6396             else
6397                 pkiDebug("#%d cert = %s is invalid\n", i, buf);
6398                 sk_X509_NAME_push(sk_xn, xn);
6399         }
6400 
6401         if (krb5_trusted_certifiers[i]->issuerAndSerialNumber.data != NULL) {
6402             p = krb5_trusted_certifiers[i]->issuerAndSerialNumber.data;
6403             is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p,
6404                 (int)krb5_trusted_certifiers[i]->issuerAndSerialNumber.length);
6405             if (is == NULL)
6406                 goto cleanup;
6407             X509_NAME_oneline(is->issuer, buf, sizeof(buf));
6408             if (td_type == TD_TRUSTED_CERTIFIERS)
6409                 pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
6410                          buf, ASN1_INTEGER_get(is->serial));
6411             else
6412                 pkiDebug("#%d issuer = %s serial = %ld is invalid\n", i, buf,
6413                          ASN1_INTEGER_get(is->serial));
6414             PKCS7_ISSUER_AND_SERIAL_free(is);
6415         }
6416 
6417         if (krb5_trusted_certifiers[i]->subjectKeyIdentifier.data != NULL) {
6418             p = krb5_trusted_certifiers[i]->subjectKeyIdentifier.data;
6419             id = d2i_ASN1_OCTET_STRING(NULL, &p,
6420                 (int)krb5_trusted_certifiers[i]->subjectKeyIdentifier.length);
6421             if (id == NULL)
6422                 goto cleanup;
6423             /* XXX */
6424             ASN1_OCTET_STRING_free(id);
6425         }
6426         i++;
6427     }
6428     /* XXX Since we not doing anything with received trusted certifiers
6429      * return an error. this is the place where we can pick a different
6430      * client certificate based on the information in td_trusted_certifiers
6431      */
6432     retval = KRB5KDC_ERR_PREAUTH_FAILED;
6433 cleanup:
6434     if (sk_xn != NULL)
6435         sk_X509_NAME_pop_free(sk_xn, X509_NAME_free);
6436 
6437     return retval;
6438 }
6439 
6440 static BIO *
6441 pkcs7_dataDecode(krb5_context context,
6442                  pkinit_identity_crypto_context id_cryptoctx,
6443                  PKCS7 *p7)
6444 {
6445     int i = 0;
6446     unsigned int jj = 0, tmp_len = 0;
6447     BIO *out=NULL,*etmp=NULL,*bio=NULL;
6448     unsigned char *tmp=NULL;
6449     ASN1_OCTET_STRING *data_body=NULL;
6450     const EVP_CIPHER *evp_cipher=NULL;
6451     EVP_CIPHER_CTX *evp_ctx=NULL;
6452     X509_ALGOR *enc_alg=NULL;
6453     STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
6454 /* Solaris Kerberos: Not used */
6455 #if 0
6456     X509_ALGOR *xalg=NULL;
6457 #endif
6458     PKCS7_RECIP_INFO *ri=NULL;
6459     X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
6460         id_cryptoctx->cert_index);
6461 
6462     p7->state=PKCS7_S_HEADER;
6463 
6464     rsk=p7->d.enveloped->recipientinfo;
6465     enc_alg=p7->d.enveloped->enc_data->algorithm;
6466     data_body=p7->d.enveloped->enc_data->enc_data;
6467     evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
6468     if (evp_cipher == NULL) {
6469         PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
6470         goto cleanup;
6471     }
6472 /* Solaris Kerberos: Not used */
6473 #if 0
6474     xalg=p7->d.enveloped->enc_data->algorithm;
6475 #endif
6476 
6477     if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
6478         PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
6479         goto cleanup;
6480     }
6481 
6482     /* It was encrypted, we need to decrypt the secret key
6483      * with the private key */
6484 
6485     /* Find the recipientInfo which matches the passed certificate
6486      * (if any)
6487      */
6488 
6489     if (cert) {
6490         for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6491             int tmp_ret = 0;
6492             ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6493             tmp_ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
6494                                     cert->cert_info->issuer);
6495             if (!tmp_ret) {
6496                 tmp_ret = M_ASN1_INTEGER_cmp(cert->cert_info->serialNumber,
6497                                              ri->issuer_and_serial->serial);
6498                 if (!tmp_ret)
6499                     break;
6500             }
6501             ri=NULL;
6502         }
6503         if (ri == NULL) {
6504             PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6505                      PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
6506             goto cleanup;
6507         }
6508         
6509     }
6510 
6511     /* If we haven't got a certificate try each ri in turn */
6512 
6513     if (cert == NULL) {
6514         for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6515             ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6516             jj = pkinit_decode_data(context, id_cryptoctx,
6517                 M_ASN1_STRING_data(ri->enc_key),
6518                 (unsigned int) M_ASN1_STRING_length(ri->enc_key),
6519                 &tmp, &tmp_len);
6520             if (jj) {
6521                 PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6522                 goto cleanup;
6523             }
6524 
6525             if (!jj && tmp_len > 0) {
6526                 jj = tmp_len;
6527                 break;
6528             }
6529 
6530             ERR_clear_error();
6531             ri = NULL;
6532         }
6533 
6534         if (ri == NULL) {
6535             PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_KEY);
6536             goto cleanup;
6537         }
6538     }
6539     else {
6540         jj = pkinit_decode_data(context, id_cryptoctx,
6541             M_ASN1_STRING_data(ri->enc_key),
6542             (unsigned int) M_ASN1_STRING_length(ri->enc_key),
6543             &tmp, &tmp_len);
6544         /* Solaris Kerberos: tmp_len is unsigned. Cannot be < 0 */
6545         if (jj || tmp_len == 0) {
6546             PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6547             goto cleanup;
6548         }
6549         jj = tmp_len;
6550     }
6551 
6552     evp_ctx=NULL;
6553     BIO_get_cipher_ctx(etmp,&evp_ctx);
6554     if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
6555         goto cleanup;
6556     if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
6557         goto cleanup;
6558 
6559     if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
6560         /* Some S/MIME clients don't use the same key
6561          * and effective key length. The key length is
6562          * determined by the size of the decrypted RSA key.
6563          */
6564         if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)jj)) {
6565             PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6566                      PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH);
6567             goto cleanup;
6568         }
6569     }
6570     if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
6571         goto cleanup;
6572 
6573     OPENSSL_cleanse(tmp,jj);
6574 
6575     if (out == NULL)
6576         out=etmp;
6577     else
6578         BIO_push(out,etmp);
6579     etmp=NULL;
6580 
6581     if (data_body->length > 0)
6582         bio = BIO_new_mem_buf(data_body->data, data_body->length);
6583     else {
6584         bio=BIO_new(BIO_s_mem());
6585         BIO_set_mem_eof_return(bio,0);
6586     }
6587     BIO_push(out,bio);
6588     bio=NULL;
6589 
6590     /* Solaris Kerberos */
6591     goto out;
6592 
6593 cleanup:
6594         if (out != NULL) BIO_free_all(out);
6595         if (etmp != NULL) BIO_free_all(etmp);
6596         if (bio != NULL) BIO_free_all(bio);
6597         out=NULL;
6598 
6599 out:
6600     if (tmp != NULL)
6601         free(tmp);
6602 
6603     return(out);
6604 }
6605 
6606 static krb5_error_code
6607 der_decode_data(unsigned char *data, long data_len,
6608                 unsigned char **out, long *out_len)
6609 {
6610     /* Solaris Kerberos */
6611     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
6612     ASN1_OCTET_STRING *s = NULL;
6613     const unsigned char *p = data;
6614 
6615     if ((s = d2i_ASN1_BIT_STRING(NULL, &p, data_len)) == NULL)
6616         goto cleanup;
6617     *out_len = s->length;
6618     if ((*out = (unsigned char *) malloc((size_t) *out_len + 1)) == NULL) {
6619         retval = ENOMEM;
6620         goto cleanup;
6621     }
6622     (void) memcpy(*out, s->data, (size_t) s->length);
6623     (*out)[s->length] = '\0';
6624 
6625     retval = 0;
6626   cleanup:
6627     if (s != NULL)
6628         ASN1_OCTET_STRING_free(s);
6629 
6630     return retval;
6631 }
6632 
6633 
6634 #ifdef DEBUG_DH
6635 static void
6636 print_dh(DH * dh, char *msg)
6637 {
6638     BIO *bio_err = NULL;
6639 
6640     bio_err = BIO_new(BIO_s_file());
6641     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6642 
6643     if (msg)
6644         BIO_puts(bio_err, (const char *)msg);
6645     if (dh)
6646         DHparams_print(bio_err, dh);
6647 
6648     BN_print(bio_err, dh->q);
6649     BIO_puts(bio_err, (const char *)"\n");
6650     BIO_free(bio_err);
6651 
6652 }
6653 
6654 static void
6655 print_pubkey(BIGNUM * key, char *msg)
6656 {
6657     BIO *bio_err = NULL;
6658 
6659     bio_err = BIO_new(BIO_s_file());
6660     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6661 
6662     if (msg)
6663         BIO_puts(bio_err, (const char *)msg);
6664     if (key)
6665         BN_print(bio_err, key);
6666     BIO_puts(bio_err, "\n");
6667 
6668     BIO_free(bio_err);
6669 
6670 }
6671 #endif
6672 
6673 /*
6674  * Solaris Kerberos:
6675  * Error message generation has changed so gettext() can be used
6676  */
6677 #if 0
6678 static char *
6679 pkinit_pkcs11_code_to_text(int err)
6680 {
6681     int i;
6682     static char uc[64];
6683 
6684     for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
6685         if (pkcs11_errstrings[i].code == err)
6686             break;
6687     if (pkcs11_errstrings[i].text != NULL)
6688         return (pkcs11_errstrings[i].text);
6689     snprintf(uc, 64, gettext("unknown code 0x%x"), err);
6690     return (uc);
6691 }
6692 #endif
6693 
6694 static char *
6695 pkinit_pkcs11_code_to_text(int err) {
6696         return pkcs11_error_table(err);
6697 }