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