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  */
  35 
  36 #include <errno.h>
  37 #include <string.h>
  38 #include <stdio.h>
  39 #include <stdlib.h>
  40 #include <dlfcn.h>
  41 #include <unistd.h>
  42 #include <dirent.h>
  43 
  44 
  45 /* Solaris Kerberos */
  46 #include <libintl.h>
  47 #include <assert.h>
  48 #include <security/pam_appl.h>
  49 #include <ctype.h>
  50 #include "k5-int.h"
  51 #include <ctype.h>
  52 
  53 /*
  54  * Q: What is this SILLYDECRYPT stuff about?
  55  * A: When using the ActivCard Linux pkcs11 library (v2.0.1),
  56  *    the decrypt function fails.  By inserting an extra
  57  *    function call, which serves nothing but to change the
  58  *    stack, we were able to work around the issue.  If the
  59  *    ActivCard library is fixed in the future, this
  60  *    definition and related code can be removed.
  61  */
  62 #define SILLYDECRYPT
  63 
  64 #include "pkinit_crypto_openssl.h"
  65 
  66 /*
  67  * Solaris Kerberos:
  68  * Changed to a switch statement so gettext() can be used
  69  * for internationization.
  70  * Use defined constants rather than raw numbers for error codes.
  71  */
  72 static char *
  73 pkcs11_error_table(short code) {
  74         switch (code) {
  75             case CKR_OK:
  76                 return (gettext("ok"));
  77             case CKR_CANCEL:
  78                 return (gettext("cancel"));
  79             case CKR_HOST_MEMORY:
  80                 return (gettext("host memory"));
  81             case CKR_SLOT_ID_INVALID:
  82                 return (gettext("slot id invalid"));
  83             case CKR_GENERAL_ERROR:
  84                 return (gettext("general error"));
  85             case CKR_FUNCTION_FAILED:
  86                 return (gettext("function failed"));
  87             case CKR_ARGUMENTS_BAD:
  88                 return (gettext("arguments bad"));
  89             case CKR_NO_EVENT:
  90                 return (gettext("no event"));
  91             case CKR_NEED_TO_CREATE_THREADS:
  92                 return (gettext("need to create threads"));
  93             case CKR_CANT_LOCK:
  94                 return (gettext("cant lock"));
  95             case CKR_ATTRIBUTE_READ_ONLY:
  96                 return (gettext("attribute read only"));
  97             case CKR_ATTRIBUTE_SENSITIVE:
  98                 return (gettext("attribute sensitive"));
  99             case CKR_ATTRIBUTE_TYPE_INVALID:
 100                 return (gettext("attribute type invalid"));
 101             case CKR_ATTRIBUTE_VALUE_INVALID:
 102                 return (gettext("attribute value invalid"));
 103             case CKR_DATA_INVALID:
 104                 return (gettext("data invalid"));
 105             case CKR_DATA_LEN_RANGE:
 106                 return (gettext("data len range"));
 107             case CKR_DEVICE_ERROR:
 108                 return (gettext("device error"));
 109             case CKR_DEVICE_MEMORY:
 110                 return (gettext("device memory"));
 111             case CKR_DEVICE_REMOVED:
 112                 return (gettext("device removed"));
 113             case CKR_ENCRYPTED_DATA_INVALID:
 114                 return (gettext("encrypted data invalid"));
 115             case CKR_ENCRYPTED_DATA_LEN_RANGE:
 116                 return (gettext("encrypted data len range"));
 117             case CKR_FUNCTION_CANCELED:
 118                 return (gettext("function canceled"));
 119             case CKR_FUNCTION_NOT_PARALLEL:
 120                 return (gettext("function not parallel"));
 121             case CKR_FUNCTION_NOT_SUPPORTED:
 122                 return (gettext("function not supported"));
 123             case CKR_KEY_HANDLE_INVALID:
 124                 return (gettext("key handle invalid"));
 125             case CKR_KEY_SIZE_RANGE:
 126                 return (gettext("key size range"));
 127             case CKR_KEY_TYPE_INCONSISTENT:
 128                 return (gettext("key type inconsistent"));
 129             case CKR_KEY_NOT_NEEDED:
 130                 return (gettext("key not needed"));
 131             case CKR_KEY_CHANGED:
 132                 return (gettext("key changed"));
 133             case CKR_KEY_NEEDED:
 134                 return (gettext("key needed"));
 135             case CKR_KEY_INDIGESTIBLE:
 136                 return (gettext("key indigestible"));
 137             case CKR_KEY_FUNCTION_NOT_PERMITTED:
 138                 return (gettext("key function not permitted"));
 139             case CKR_KEY_NOT_WRAPPABLE:
 140                 return (gettext("key not wrappable"));
 141             case CKR_KEY_UNEXTRACTABLE:
 142                 return (gettext("key unextractable"));
 143             case CKR_MECHANISM_INVALID:
 144                 return (gettext("mechanism invalid"));
 145             case CKR_MECHANISM_PARAM_INVALID:
 146                 return (gettext("mechanism param invalid"));
 147             case CKR_OBJECT_HANDLE_INVALID:
 148                 return (gettext("object handle invalid"));
 149             case CKR_OPERATION_ACTIVE:
 150                 return (gettext("operation active"));
 151             case CKR_OPERATION_NOT_INITIALIZED:
 152                 return (gettext("operation not initialized"));
 153             case CKR_PIN_INCORRECT:
 154                 return (gettext("pin incorrect"));
 155             case CKR_PIN_INVALID:
 156                 return (gettext("pin invalid"));
 157             case CKR_PIN_LEN_RANGE:
 158                 return (gettext("pin len range"));
 159             case CKR_PIN_EXPIRED:
 160                 return (gettext("pin expired"));
 161             case CKR_PIN_LOCKED:
 162                 return (gettext("pin locked"));
 163             case CKR_SESSION_CLOSED:
 164                 return (gettext("session closed"));
 165             case CKR_SESSION_COUNT:
 166                 return (gettext("session count"));
 167             case CKR_SESSION_HANDLE_INVALID:
 168                 return (gettext("session handle invalid"));
 169             case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
 170                 return (gettext("session parallel not supported"));
 171             case CKR_SESSION_READ_ONLY:
 172                 return (gettext("session read only"));
 173             case CKR_SESSION_EXISTS:
 174                 return (gettext("session exists"));
 175             case CKR_SESSION_READ_ONLY_EXISTS:
 176                 return (gettext("session read only exists"));
 177             case CKR_SESSION_READ_WRITE_SO_EXISTS:
 178                 return (gettext("session read write so exists"));
 179             case CKR_SIGNATURE_INVALID:
 180                 return (gettext("signature invalid"));
 181             case CKR_SIGNATURE_LEN_RANGE:
 182                 return (gettext("signature len range"));
 183             case CKR_TEMPLATE_INCOMPLETE:
 184                 return (gettext("template incomplete"));
 185             case CKR_TEMPLATE_INCONSISTENT:
 186                 return (gettext("template inconsistent"));
 187             case CKR_TOKEN_NOT_PRESENT:
 188                 return (gettext("token not present"));
 189             case CKR_TOKEN_NOT_RECOGNIZED:
 190                 return (gettext("token not recognized"));
 191             case CKR_TOKEN_WRITE_PROTECTED:
 192                 return (gettext("token write protected"));
 193             case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
 194                 return (gettext("unwrapping key handle invalid"));
 195             case CKR_UNWRAPPING_KEY_SIZE_RANGE:
 196                 return (gettext("unwrapping key size range"));
 197             case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
 198                 return (gettext("unwrapping key type inconsistent"));
 199             case CKR_USER_ALREADY_LOGGED_IN:
 200                 return (gettext("user already logged in"));
 201             case CKR_USER_NOT_LOGGED_IN:
 202                 return (gettext("user not logged in"));
 203             case CKR_USER_PIN_NOT_INITIALIZED:
 204                 return (gettext("user pin not initialized"));
 205             case CKR_USER_TYPE_INVALID:
 206                 return (gettext("user type invalid"));
 207             case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
 208                 return (gettext("user another already logged in"));
 209             case CKR_USER_TOO_MANY_TYPES:
 210                 return (gettext("user too many types"));
 211             case CKR_WRAPPED_KEY_INVALID:
 212                 return (gettext("wrapped key invalid"));
 213             case CKR_WRAPPED_KEY_LEN_RANGE:
 214                 return (gettext("wrapped key len range"));
 215             case CKR_WRAPPING_KEY_HANDLE_INVALID:
 216                 return (gettext("wrapping key handle invalid"));
 217             case CKR_WRAPPING_KEY_SIZE_RANGE:
 218                 return (gettext("wrapping key size range"));
 219             case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
 220                 return (gettext("wrapping key type inconsistent"));
 221             case CKR_RANDOM_SEED_NOT_SUPPORTED:
 222                 return (gettext("random seed not supported"));
 223             case CKR_RANDOM_NO_RNG:
 224                 return (gettext("random no rng"));
 225             case CKR_DOMAIN_PARAMS_INVALID:
 226                 return (gettext("domain params invalid"));
 227             case CKR_BUFFER_TOO_SMALL:
 228                 return (gettext("buffer too small"));
 229             case CKR_SAVED_STATE_INVALID:
 230                 return (gettext("saved state invalid"));
 231             case CKR_INFORMATION_SENSITIVE:
 232                 return (gettext("information sensitive"));
 233             case CKR_STATE_UNSAVEABLE:
 234                 return (gettext("state unsaveable"));
 235             case CKR_CRYPTOKI_NOT_INITIALIZED:
 236                 return (gettext("cryptoki not initialized"));
 237             case CKR_CRYPTOKI_ALREADY_INITIALIZED:
 238                 return (gettext("cryptoki already initialized"));
 239             case CKR_MUTEX_BAD:
 240                 return (gettext("mutex bad"));
 241             case CKR_MUTEX_NOT_LOCKED:
 242                 return (gettext("mutex not locked"));
 243             case CKR_FUNCTION_REJECTED:
 244                 return (gettext("function rejected"));
 245             default:
 246                 return (gettext("unknown error"));
 247         }
 248 }
 249 
 250 /* DH parameters */
 251 unsigned char pkinit_1024_dhprime[128] = {
 252     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 253     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
 254     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 255     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
 256     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
 257     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 258     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
 259     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
 260     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 261     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
 262     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
 263     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 264     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
 265     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
 266     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
 267     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 268 };
 269 
 270 unsigned char pkinit_2048_dhprime[2048/8] = {
 271     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 272     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
 273     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 274     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
 275     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
 276     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 277     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
 278     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
 279     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 280     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
 281     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
 282     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 283     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
 284     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
 285     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
 286     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
 287     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
 288     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
 289     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
 290     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
 291     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
 292     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
 293     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
 294     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
 295     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
 296     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
 297     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
 298     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
 299     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
 300     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
 301     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
 302     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 303 };
 304 
 305 unsigned char pkinit_4096_dhprime[4096/8] = {
 306     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 307     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
 308     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 309     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
 310     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
 311     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 312     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
 313     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
 314     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 315     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
 316     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
 317     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 318     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
 319     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
 320     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
 321     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
 322     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
 323     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
 324     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
 325     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
 326     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
 327     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
 328     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
 329     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
 330     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
 331     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
 332     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
 333     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
 334     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
 335     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
 336     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
 337     0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
 338     0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
 339     0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
 340     0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
 341     0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
 342     0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
 343     0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
 344     0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
 345     0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
 346     0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
 347     0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
 348     0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
 349     0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
 350     0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
 351     0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
 352     0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
 353     0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
 354     0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
 355     0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
 356     0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
 357     0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
 358     0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
 359     0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
 360     0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
 361     0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
 362     0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
 363     0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
 364     0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
 365     0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
 366     0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
 367     0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
 368     0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
 369     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 370 };
 371 
 372 /* Solaris Kerberos */
 373 static k5_mutex_t oids_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
 374 static int pkinit_oids_refs = 0;
 375 
 376 krb5_error_code
 377 pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) {
 378 
 379     krb5_error_code retval = ENOMEM;
 380     pkinit_plg_crypto_context ctx = NULL;
 381 
 382     /* initialize openssl routines */
 383     /* Solaris Kerberos */
 384     retval = openssl_init();
 385     if (retval != 0)
 386         goto out;
 387 
 388     ctx = (pkinit_plg_crypto_context)malloc(sizeof(*ctx));
 389     if (ctx == NULL)
 390         goto out;
 391     (void) memset(ctx, 0, sizeof(*ctx));
 392 
 393     pkiDebug("%s: initializing openssl crypto context at %p\n",
 394              __FUNCTION__, ctx);
 395     retval = pkinit_init_pkinit_oids(ctx);
 396     if (retval)
 397         goto out;
 398 
 399     retval = pkinit_init_dh_params(ctx);
 400     if (retval)
 401         goto out;
 402 
 403     *cryptoctx = ctx;
 404 
 405 out:
 406     if (retval && ctx != NULL)
 407             pkinit_fini_plg_crypto(ctx);
 408 
 409     return retval;
 410 }
 411 
 412 void
 413 pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)
 414 {
 415     pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx);
 416 
 417     if (cryptoctx == NULL)
 418         return;
 419     pkinit_fini_pkinit_oids(cryptoctx);
 420     pkinit_fini_dh_params(cryptoctx);
 421     free(cryptoctx);
 422 }
 423 
 424 krb5_error_code
 425 pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
 426 {
 427     krb5_error_code retval = ENOMEM;
 428     pkinit_identity_crypto_context ctx = NULL;
 429 
 430     ctx = (pkinit_identity_crypto_context)malloc(sizeof(*ctx));
 431     if (ctx == NULL)
 432         goto out;
 433     (void) memset(ctx, 0, sizeof(*ctx));
 434 
 435     retval = pkinit_init_certs(ctx);
 436     if (retval)
 437         goto out;
 438 
 439     retval = pkinit_init_pkcs11(ctx);
 440     if (retval)
 441         goto out;
 442 
 443     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
 444     *idctx = ctx;
 445 
 446 out:
 447     if (retval) {
 448         if (ctx)
 449             pkinit_fini_identity_crypto(ctx);
 450     }
 451 
 452     return retval;
 453 }
 454 
 455 void
 456 pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
 457 {
 458     if (idctx == NULL)
 459         return;
 460 
 461     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, idctx);
 462     pkinit_fini_certs(idctx);
 463     pkinit_fini_pkcs11(idctx);
 464     free(idctx);
 465 }
 466 
 467 krb5_error_code
 468 pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
 469 {
 470 
 471     pkinit_req_crypto_context ctx = NULL;
 472 
 473     /* Solaris Kerberos */
 474     if (cryptoctx == NULL)
 475         return EINVAL;
 476 
 477     ctx = (pkinit_req_crypto_context)malloc(sizeof(*ctx));
 478     if (ctx == NULL)
 479         return ENOMEM;
 480     (void) memset(ctx, 0, sizeof(*ctx));
 481 
 482     ctx->dh = NULL;
 483     ctx->received_cert = NULL;
 484 
 485     *cryptoctx = ctx;
 486 
 487     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
 488 
 489     return 0;
 490 }
 491 
 492 void
 493 pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
 494 {
 495     if (req_cryptoctx == NULL)
 496         return;
 497 
 498     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, req_cryptoctx);
 499     if (req_cryptoctx->dh != NULL)
 500       DH_free(req_cryptoctx->dh);
 501     if (req_cryptoctx->received_cert != NULL)
 502       X509_free(req_cryptoctx->received_cert);
 503 
 504     free(req_cryptoctx);
 505 }
 506 
 507 static krb5_error_code
 508 pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
 509 {
 510     krb5_error_code retval = ENOMEM;
 511     int nid = 0;
 512 
 513     /*
 514      * If OpenSSL already knows about the OID, use the
 515      * existing definition. Otherwise, create an OID object.
 516      */
 517     #define CREATE_OBJ_IF_NEEDED(oid, vn, sn, ln) \
 518         nid = OBJ_txt2nid(oid); \
 519         if (nid == NID_undef) { \
 520             nid = OBJ_create(oid, sn, ln); \
 521             if (nid == NID_undef) { \
 522                 pkiDebug("Error creating oid object for '%s'\n", oid); \
 523                 goto out; \
 524             } \
 525         } \
 526         ctx->vn = OBJ_nid2obj(nid);
 527     
 528     /* Solaris Kerberos */
 529     retval = k5_mutex_lock(&oids_mutex);
 530     if (retval != 0)
 531         goto out;
 532 
 533     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.2", id_pkinit_san,
 534                          "id-pkinit-san", "KRB5PrincipalName");
 535 
 536     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.1", id_pkinit_authData,
 537                          "id-pkinit-authdata", "PKINIT signedAuthPack");
 538 
 539     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.2", id_pkinit_DHKeyData,
 540                          "id-pkinit-DHKeyData", "PKINIT dhSignedData");
 541 
 542     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.3", id_pkinit_rkeyData,
 543                          "id-pkinit-rkeyData", "PKINIT encKeyPack");
 544 
 545     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.4", id_pkinit_KPClientAuth,
 546                          "id-pkinit-KPClientAuth", "PKINIT Client EKU");
 547 
 548     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.5", id_pkinit_KPKdc,
 549                          "id-pkinit-KPKdc", "KDC EKU");
 550 
 551 #if 0
 552     CREATE_OBJ_IF_NEEDED("1.2.840.113549.1.7.1", id_pkinit_authData9,
 553                          "id-pkcs7-data", "PKCS7 data");
 554 #else
 555     /* See note in pkinit_pkcs7type2oid() */
 556     ctx->id_pkinit_authData9 = NULL;
 557 #endif
 558 
 559     CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.2", id_ms_kp_sc_logon,
 560                          "id-ms-kp-sc-logon EKU", "Microsoft SmartCard Login EKU");
 561 
 562     CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.3", id_ms_san_upn,
 563                          "id-ms-san-upn", "Microsoft Universal Principal Name");
 564 
 565     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.5.7.3.1", id_kp_serverAuth,
 566                          "id-kp-serverAuth EKU", "Server Authentication EKU");
 567 
 568     /* Success */
 569     retval = 0;
 570     
 571     pkinit_oids_refs++;
 572     /* Solaris Kerberos */
 573     k5_mutex_unlock(&oids_mutex);
 574 
 575 out:
 576     return retval;
 577 }
 578 
 579 static krb5_error_code
 580 get_cert(char *filename, X509 **retcert)
 581 {
 582     X509 *cert = NULL;
 583     BIO *tmp = NULL;
 584     int code;
 585     krb5_error_code retval;
 586 
 587     if (filename == NULL || retcert == NULL)
 588         return EINVAL;
 589 
 590     *retcert = NULL;
 591 
 592     tmp = BIO_new(BIO_s_file());
 593     if (tmp == NULL)
 594         return ENOMEM;
 595 
 596     code = BIO_read_filename(tmp, filename);
 597     if (code == 0) {
 598         retval = errno;
 599         goto cleanup;
 600     }
 601 
 602     cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL);
 603     if (cert == NULL) {
 604         retval = EIO;
 605         pkiDebug("failed to read certificate from %s\n", filename);
 606         goto cleanup;
 607     }
 608     *retcert = cert;
 609     retval = 0;
 610 cleanup:
 611     if (tmp != NULL)
 612         BIO_free(tmp);
 613     return retval;
 614 }
 615 
 616 static krb5_error_code
 617 get_key(char *filename, EVP_PKEY **retkey)
 618 {
 619     EVP_PKEY *pkey = NULL;
 620     BIO *tmp = NULL;
 621     int code;
 622     krb5_error_code retval;
 623 
 624     if (filename == NULL || retkey == NULL)
 625         return EINVAL;
 626 
 627     tmp = BIO_new(BIO_s_file());
 628     if (tmp == NULL)
 629         return ENOMEM;
 630 
 631     code = BIO_read_filename(tmp, filename);
 632     if (code == 0) {
 633         retval = errno;
 634         goto cleanup;
 635     }
 636     pkey = (EVP_PKEY *) PEM_read_bio_PrivateKey(tmp, NULL, NULL, NULL);
 637     if (pkey == NULL) {
 638         retval = EIO;
 639         pkiDebug("failed to read private key from %s\n", filename);
 640         goto cleanup;
 641     }
 642     *retkey = pkey;
 643     retval = 0;
 644 cleanup:
 645     if (tmp != NULL)
 646         BIO_free(tmp);
 647     return retval;
 648 }
 649 
 650 static void
 651 pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
 652 {
 653     if (ctx == NULL)
 654         return;
 655 
 656     /* Only call OBJ_cleanup once! */
 657     /* Solaris Kerberos: locking */
 658     k5_mutex_lock(&oids_mutex);
 659     if (--pkinit_oids_refs == 0)
 660         OBJ_cleanup();
 661     k5_mutex_unlock(&oids_mutex);
 662 }
 663 
 664 static krb5_error_code
 665 pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
 666 {
 667     krb5_error_code retval = ENOMEM;
 668 
 669     plgctx->dh_1024 = DH_new();
 670     if (plgctx->dh_1024 == NULL)
 671         goto cleanup;
 672     plgctx->dh_1024->p = BN_bin2bn(pkinit_1024_dhprime,
 673         sizeof(pkinit_1024_dhprime), NULL);
 674     if ((plgctx->dh_1024->g = BN_new()) == NULL ||
 675         (plgctx->dh_1024->q = BN_new()) == NULL)
 676         goto cleanup;
 677     BN_set_word(plgctx->dh_1024->g, DH_GENERATOR_2);
 678     BN_rshift1(plgctx->dh_1024->q, plgctx->dh_1024->p);
 679 
 680     plgctx->dh_2048 = DH_new();
 681     if (plgctx->dh_2048 == NULL)
 682         goto cleanup;
 683     plgctx->dh_2048->p = BN_bin2bn(pkinit_2048_dhprime,
 684         sizeof(pkinit_2048_dhprime), NULL);
 685     if ((plgctx->dh_2048->g = BN_new()) == NULL ||
 686         (plgctx->dh_2048->q = BN_new()) == NULL)
 687         goto cleanup;
 688     BN_set_word(plgctx->dh_2048->g, DH_GENERATOR_2);
 689     BN_rshift1(plgctx->dh_2048->q, plgctx->dh_2048->p);
 690 
 691     plgctx->dh_4096 = DH_new();
 692     if (plgctx->dh_4096 == NULL)
 693         goto cleanup;
 694     plgctx->dh_4096->p = BN_bin2bn(pkinit_4096_dhprime,
 695         sizeof(pkinit_4096_dhprime), NULL);
 696     if ((plgctx->dh_4096->g = BN_new()) == NULL ||
 697         (plgctx->dh_4096->q = BN_new()) == NULL)
 698         goto cleanup;
 699     BN_set_word(plgctx->dh_4096->g, DH_GENERATOR_2);
 700     BN_rshift1(plgctx->dh_4096->q, plgctx->dh_4096->p);
 701 
 702     retval = 0;
 703 
 704 cleanup:
 705     if (retval)
 706         pkinit_fini_dh_params(plgctx);
 707 
 708     return retval;
 709 }
 710 
 711 static void
 712 pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
 713 {
 714     if (plgctx->dh_1024 != NULL)
 715         DH_free(plgctx->dh_1024);
 716     if (plgctx->dh_2048 != NULL)
 717         DH_free(plgctx->dh_2048);
 718     if (plgctx->dh_4096 != NULL)
 719         DH_free(plgctx->dh_4096);
 720 
 721     plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
 722 }
 723 
 724 static krb5_error_code
 725 pkinit_init_certs(pkinit_identity_crypto_context ctx)
 726 {
 727     /* Solaris Kerberos */
 728     int i;
 729 
 730     for (i = 0; i < MAX_CREDS_ALLOWED; i++)
 731         ctx->creds[i] = NULL;
 732     ctx->my_certs = NULL;
 733     ctx->cert_index = 0;
 734     ctx->my_key = NULL;
 735     ctx->trustedCAs = NULL;
 736     ctx->intermediateCAs = NULL;
 737     ctx->revoked = NULL;
 738 
 739     return 0;
 740 }
 741 
 742 static void
 743 pkinit_fini_certs(pkinit_identity_crypto_context ctx)
 744 {
 745     if (ctx == NULL)
 746         return;
 747 
 748     if (ctx->my_certs != NULL)
 749         sk_X509_pop_free(ctx->my_certs, X509_free);
 750 
 751     if (ctx->my_key != NULL)
 752         EVP_PKEY_free(ctx->my_key);
 753 
 754     if (ctx->trustedCAs != NULL)
 755         sk_X509_pop_free(ctx->trustedCAs, X509_free);
 756 
 757     if (ctx->intermediateCAs != NULL)
 758         sk_X509_pop_free(ctx->intermediateCAs, X509_free);
 759 
 760     if (ctx->revoked != NULL)
 761         sk_X509_CRL_pop_free(ctx->revoked, X509_CRL_free);
 762 }
 763 
 764 static krb5_error_code
 765 pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)
 766 {
 767     /* Solaris Kerberos */
 768 
 769 #ifndef WITHOUT_PKCS11
 770     ctx->p11_module_name = strdup(PKCS11_MODNAME);
 771     if (ctx->p11_module_name == NULL)
 772         return ENOMEM;
 773     ctx->p11_module = NULL;
 774     ctx->slotid = PK_NOSLOT;
 775     ctx->token_label = NULL;
 776     ctx->cert_label = NULL;
 777     ctx->PIN = NULL;
 778     ctx->session = CK_INVALID_HANDLE;
 779     ctx->p11 = NULL;
 780     ctx->p11flags = 0; /* Solaris Kerberos */
 781 #endif
 782     ctx->pkcs11_method = 0;
 783     (void) memset(ctx->creds, 0, sizeof(ctx->creds));
 784 
 785     return 0;
 786 }
 787 
 788 static void
 789 pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
 790 {
 791 #ifndef WITHOUT_PKCS11
 792     if (ctx == NULL)
 793         return;
 794 
 795     if (ctx->p11 != NULL) {
 796         if (ctx->session != CK_INVALID_HANDLE) {
 797             ctx->p11->C_CloseSession(ctx->session);
 798             ctx->session = CK_INVALID_HANDLE;
 799         }
 800         /*
 801          * Solaris Kerberos:
 802          * Only call C_Finalize if the process was not already using pkcs11.
 803          */
 804         if (ctx->finalize_pkcs11 == TRUE)
 805             ctx->p11->C_Finalize(NULL_PTR);
 806 
 807         ctx->p11 = NULL;
 808     }
 809     if (ctx->p11_module != NULL) {
 810         pkinit_C_UnloadModule(ctx->p11_module);
 811         ctx->p11_module = NULL;
 812     }
 813     if (ctx->p11_module_name != NULL)
 814         free(ctx->p11_module_name);
 815     if (ctx->token_label != NULL)
 816         free(ctx->token_label);
 817     if (ctx->cert_id != NULL)
 818         free(ctx->cert_id);
 819     if (ctx->cert_label != NULL)
 820         free(ctx->cert_label);
 821     if (ctx->PIN != NULL) {
 822         (void) memset(ctx->PIN, 0, strlen(ctx->PIN));
 823         free(ctx->PIN);
 824     }
 825 #endif
 826 }
 827 
 828 krb5_error_code
 829 pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
 830                              krb5_prompter_fct prompter,
 831                              void *prompter_data)
 832 {
 833     id_cryptoctx->prompter = prompter;
 834     id_cryptoctx->prompter_data = prompter_data;
 835 
 836     return 0;
 837 }
 838 
 839 /* ARGSUSED */
 840 krb5_error_code
 841 cms_signeddata_create(krb5_context context,
 842                       pkinit_plg_crypto_context plg_cryptoctx,
 843                       pkinit_req_crypto_context req_cryptoctx,
 844                       pkinit_identity_crypto_context id_cryptoctx,
 845                       int cms_msg_type,
 846                       int include_certchain,
 847                       unsigned char *data,
 848                       unsigned int data_len,
 849                       unsigned char **signed_data,
 850                       unsigned int *signed_data_len)
 851 {
 852     /* Solaris Kerberos */
 853     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
 854     PKCS7  *p7 = NULL, *inner_p7 = NULL;
 855     PKCS7_SIGNED *p7s = NULL;
 856     PKCS7_SIGNER_INFO *p7si = NULL;
 857     unsigned char *p;
 858     ASN1_TYPE *pkinit_data = NULL;
 859     STACK_OF(X509) * cert_stack = NULL;
 860     ASN1_OCTET_STRING *digest_attr = NULL;
 861     EVP_MD_CTX ctx, ctx2;
 862     const EVP_MD *md_tmp = NULL;
 863     unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
 864     unsigned char *digestInfo_buf = NULL, *abuf = NULL;
 865     unsigned int md_len, md_len2, alen, digestInfo_len;
 866     STACK_OF(X509_ATTRIBUTE) * sk;
 867     unsigned char *sig = NULL;
 868     unsigned int sig_len = 0;
 869     X509_ALGOR *alg = NULL;
 870     ASN1_OCTET_STRING *digest = NULL;
 871     unsigned int alg_len = 0, digest_len = 0;
 872     unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
 873     X509 *cert = NULL;
 874     ASN1_OBJECT *oid = NULL;
 875 
 876     /* Solaris Kerberos */
 877     if (signed_data == NULL)
 878         return EINVAL;
 879 
 880     if (signed_data_len == NULL)
 881         return EINVAL;
 882 
 883     /* start creating PKCS7 data */
 884     if ((p7 = PKCS7_new()) == NULL)
 885         goto cleanup;
 886     p7->type = OBJ_nid2obj(NID_pkcs7_signed);
 887 
 888     if ((p7s = PKCS7_SIGNED_new()) == NULL)
 889         goto cleanup;
 890     p7->d.sign = p7s;
 891     if (!ASN1_INTEGER_set(p7s->version, 3))
 892         goto cleanup;
 893 
 894     /* create a cert chain that has at least the signer's certificate */
 895     if ((cert_stack = sk_X509_new_null()) == NULL)
 896         goto cleanup;
 897 
 898     cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
 899     if (!include_certchain) {
 900         pkiDebug("only including signer's certificate\n");
 901         sk_X509_push(cert_stack, X509_dup(cert));
 902     } else {
 903         /* create a cert chain */
 904         X509_STORE *certstore = NULL;
 905         X509_STORE_CTX certctx;
 906         STACK_OF(X509) *certstack = NULL;
 907         char buf[DN_BUF_LEN];
 908         int i = 0, size = 0;
 909 
 910         if ((certstore = X509_STORE_new()) == NULL)
 911             goto cleanup;
 912         pkiDebug("building certificate chain\n");
 913         X509_STORE_set_verify_cb_func(certstore, openssl_callback);
 914         X509_STORE_CTX_init(&certctx, certstore, cert,
 915                             id_cryptoctx->intermediateCAs);
 916         X509_STORE_CTX_trusted_stack(&certctx, id_cryptoctx->trustedCAs);
 917         /* Solaris Kerberos */
 918         if (X509_verify_cert(&certctx) <= 0) {
 919             pkiDebug("failed to create a certificate chain: %s\n", 
 920             X509_verify_cert_error_string(X509_STORE_CTX_get_error(&certctx)));
 921             if (!sk_X509_num(id_cryptoctx->trustedCAs)) 
 922                 pkiDebug("No trusted CAs found. Check your X509_anchors\n");
 923             goto cleanup;
 924         }
 925         certstack = X509_STORE_CTX_get1_chain(&certctx);
 926         size = sk_X509_num(certstack);
 927         pkiDebug("size of certificate chain = %d\n", size);
 928         for(i = 0; i < size - 1; i++) {
 929             X509 *x = sk_X509_value(certstack, i);
 930             X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
 931             pkiDebug("cert #%d: %s\n", i, buf);
 932             sk_X509_push(cert_stack, X509_dup(x));
 933         }
 934         X509_STORE_CTX_cleanup(&certctx);
 935         X509_STORE_free(certstore);
 936         sk_X509_pop_free(certstack, X509_free);
 937     }
 938     p7s->cert = cert_stack;
 939 
 940     /* fill-in PKCS7_SIGNER_INFO */
 941     if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
 942         goto cleanup;
 943     if (!ASN1_INTEGER_set(p7si->version, 1))
 944         goto cleanup;
 945     if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
 946                        X509_get_issuer_name(cert)))
 947         goto cleanup;
 948     /* because ASN1_INTEGER_set is used to set a 'long' we will do
 949      * things the ugly way. */
 950     M_ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
 951     if (!(p7si->issuer_and_serial->serial =
 952           M_ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
 953         goto cleanup;
 954 
 955     /* will not fill-out EVP_PKEY because it's on the smartcard */
 956 
 957     /* Set digest algs */
 958     p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
 959 
 960     if (p7si->digest_alg->parameter != NULL)
 961         ASN1_TYPE_free(p7si->digest_alg->parameter);
 962     if ((p7si->digest_alg->parameter = ASN1_TYPE_new()) == NULL)
 963         goto cleanup;
 964     p7si->digest_alg->parameter->type = V_ASN1_NULL;
 965 
 966     /* Set sig algs */
 967     if (p7si->digest_enc_alg->parameter != NULL)
 968         ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
 969     p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
 970     if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
 971         goto cleanup;
 972     p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
 973 
 974     /* pick the correct oid for the eContentInfo */
 975     oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
 976     if (oid == NULL)
 977         goto cleanup;
 978 
 979     if (cms_msg_type == CMS_SIGN_DRAFT9) {
 980         /* don't include signed attributes for pa-type 15 request */
 981         abuf = data;
 982         alen = data_len;
 983     } else {
 984         /* add signed attributes */
 985         /* compute sha1 digest over the EncapsulatedContentInfo */
 986         EVP_MD_CTX_init(&ctx);
 987         EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
 988         EVP_DigestUpdate(&ctx, data, data_len);
 989         md_tmp = EVP_MD_CTX_md(&ctx);
 990         EVP_DigestFinal_ex(&ctx, md_data, &md_len);
 991 
 992         /* create a message digest attr */
 993         digest_attr = ASN1_OCTET_STRING_new();
 994         ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
 995         PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
 996                                    V_ASN1_OCTET_STRING, (char *) digest_attr);
 997 
 998         /* create a content-type attr */
 999         PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType, 
1000                                    V_ASN1_OBJECT, oid);
1001 
1002         /* create the signature over signed attributes. get DER encoded value */
1003         /* This is the place where smartcard signature needs to be calculated */
1004         sk = p7si->auth_attr;
1005         alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
1006                              ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
1007         if (abuf == NULL)
1008             goto cleanup2;
1009     }
1010 
1011 #ifndef WITHOUT_PKCS11
1012     /* Some tokens can only do RSAEncryption without sha1 hash */
1013     /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
1014      * function and the hash value into an ASN.1 value of type DigestInfo
1015      * DigestInfo::=SEQUENCE {
1016      *  digestAlgorithm  AlgorithmIdentifier,
1017      *  digest OCTET STRING }
1018      */
1019     if (id_cryptoctx->pkcs11_method == 1 && 
1020             id_cryptoctx->mech == CKM_RSA_PKCS) {
1021         pkiDebug("mech = CKM_RSA_PKCS\n");
1022         EVP_MD_CTX_init(&ctx2);
1023         /* if this is not draft9 request, include digest signed attribute */
1024         if (cms_msg_type != CMS_SIGN_DRAFT9) 
1025             EVP_DigestInit_ex(&ctx2, md_tmp, NULL);
1026         else
1027             EVP_DigestInit_ex(&ctx2, EVP_sha1(), NULL);
1028         EVP_DigestUpdate(&ctx2, abuf, alen);
1029         EVP_DigestFinal_ex(&ctx2, md_data2, &md_len2);
1030 
1031         alg = X509_ALGOR_new();
1032         if (alg == NULL)
1033             goto cleanup2;
1034         alg->algorithm = OBJ_nid2obj(NID_sha1);
1035         alg->parameter = NULL;
1036         alg_len = i2d_X509_ALGOR(alg, NULL);
1037         alg_buf = (unsigned char *)malloc(alg_len);
1038         if (alg_buf == NULL)
1039             goto cleanup2;
1040 
1041         digest = ASN1_OCTET_STRING_new();
1042         if (digest == NULL)
1043             goto cleanup2;
1044         ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
1045         digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
1046         digest_buf = (unsigned char *)malloc(digest_len);
1047         if (digest_buf == NULL)
1048             goto cleanup2;
1049 
1050         digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
1051                                           V_ASN1_SEQUENCE);
1052         y = digestInfo_buf = (unsigned char *)malloc(digestInfo_len);
1053         if (digestInfo_buf == NULL)
1054             goto cleanup2;
1055         ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
1056                         V_ASN1_UNIVERSAL);
1057         i2d_X509_ALGOR(alg, &y);
1058         i2d_ASN1_OCTET_STRING(digest, &y);
1059 #ifdef DEBUG_SIG
1060         pkiDebug("signing buffer\n");
1061         print_buffer(digestInfo_buf, digestInfo_len);
1062         print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
1063 #endif
1064         retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
1065                                   digestInfo_len, &sig, &sig_len);
1066     } else
1067 #endif
1068     {
1069         pkiDebug("mech = %s\n",
1070             id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
1071         retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
1072                                   &sig, &sig_len);
1073     }
1074 #ifdef DEBUG_SIG
1075     print_buffer(sig, sig_len);
1076 #endif
1077     if (cms_msg_type != CMS_SIGN_DRAFT9) 
1078         free(abuf);
1079     if (retval)
1080         goto cleanup2;
1081 
1082     /* Add signature */
1083     if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig,
1084                          (int)sig_len)) {
1085         unsigned long err = ERR_peek_error();
1086         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1087         krb5_set_error_message(context, retval, "%s\n",
1088                                ERR_error_string(err, NULL));
1089         pkiDebug("failed to add a signed digest attribute\n");
1090         goto cleanup2;
1091     }
1092     /* adder signer_info to pkcs7 signed */
1093     if (!PKCS7_add_signer(p7, p7si))
1094         goto cleanup2;
1095 
1096     /* start on adding data to the pkcs7 signed */
1097     if ((inner_p7 = PKCS7_new()) == NULL)
1098         goto cleanup2;
1099     if ((pkinit_data = ASN1_TYPE_new()) == NULL)
1100         goto cleanup2;
1101     pkinit_data->type = V_ASN1_OCTET_STRING;
1102     if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
1103         goto cleanup2;
1104     if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
1105                                (int)data_len)) {
1106         unsigned long err = ERR_peek_error();
1107         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1108         krb5_set_error_message(context, retval, "%s\n",
1109                                ERR_error_string(err, NULL));
1110         pkiDebug("failed to add pkcs7 data\n");
1111         goto cleanup2;
1112     }
1113 
1114     if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
1115         goto cleanup2;
1116 
1117     if (p7s->contents != NULL)
1118         PKCS7_free(p7s->contents);
1119     p7s->contents = inner_p7;
1120 
1121     *signed_data_len = i2d_PKCS7(p7, NULL);
1122     if (!(*signed_data_len)) {
1123         unsigned long err = ERR_peek_error();
1124         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1125         krb5_set_error_message(context, retval, "%s\n",
1126                                ERR_error_string(err, NULL));
1127         pkiDebug("failed to der encode pkcs7\n");
1128         goto cleanup2;
1129     }
1130     if ((p = *signed_data =
1131          (unsigned char *) malloc((size_t)*signed_data_len)) == NULL)
1132         goto cleanup2;
1133 
1134     /* DER encode PKCS7 data */
1135     retval = i2d_PKCS7(p7, &p);
1136     if (!retval) {
1137         unsigned long err = ERR_peek_error();
1138         retval = KRB5KDC_ERR_PREAUTH_FAILED;
1139         krb5_set_error_message(context, retval, "%s\n",
1140                                ERR_error_string(err, NULL));
1141         pkiDebug("failed to der encode pkcs7\n");
1142         goto cleanup2;
1143     }
1144     retval = 0;
1145 
1146 #ifdef DEBUG_ASN1
1147     if (cms_msg_type == CMS_SIGN_CLIENT) {
1148         print_buffer_bin(*signed_data, *signed_data_len,
1149                          "/tmp/client_pkcs7_signeddata");
1150     } else {
1151         if (cms_msg_type == CMS_SIGN_SERVER) {
1152             print_buffer_bin(*signed_data, *signed_data_len,
1153                              "/tmp/kdc_pkcs7_signeddata");
1154         } else {
1155             print_buffer_bin(*signed_data, *signed_data_len,
1156                              "/tmp/draft9_pkcs7_signeddata");
1157         }
1158     }
1159 #endif
1160 
1161   cleanup2:
1162     if (cms_msg_type != CMS_SIGN_DRAFT9) 
1163         EVP_MD_CTX_cleanup(&ctx);
1164 #ifndef WITHOUT_PKCS11
1165     if (id_cryptoctx->pkcs11_method == 1 && 
1166             id_cryptoctx->mech == CKM_RSA_PKCS) {
1167         EVP_MD_CTX_cleanup(&ctx2);
1168         if (digest_buf != NULL)
1169             free(digest_buf);
1170         if (digestInfo_buf != NULL)
1171             free(digestInfo_buf);
1172         if (alg_buf != NULL)
1173             free(alg_buf);
1174         if (digest != NULL)
1175             ASN1_OCTET_STRING_free(digest);
1176     }
1177 #endif
1178     if (alg != NULL)
1179         X509_ALGOR_free(alg);
1180   cleanup:
1181     if (p7 != NULL) 
1182         PKCS7_free(p7);
1183     if (sig != NULL)
1184         free(sig);
1185 
1186     return retval;
1187 }
1188 
1189 krb5_error_code
1190 cms_signeddata_verify(krb5_context context,
1191                       pkinit_plg_crypto_context plgctx,
1192                       pkinit_req_crypto_context reqctx,
1193                       pkinit_identity_crypto_context idctx,
1194                       int cms_msg_type,
1195                       int require_crl_checking,
1196                       unsigned char *signed_data,
1197                       unsigned int signed_data_len,
1198                       unsigned char **data,
1199                       unsigned int *data_len,
1200                       unsigned char **authz_data,
1201                       unsigned int *authz_data_len)
1202 {
1203     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1204     PKCS7 *p7 = NULL;
1205     BIO *out = NULL;
1206     int flags = PKCS7_NOVERIFY, i = 0;
1207     unsigned int vflags = 0, size = 0;
1208     const unsigned char *p = signed_data;
1209     STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
1210     PKCS7_SIGNER_INFO *si = NULL;
1211     X509 *x = NULL;
1212     X509_STORE *store = NULL;
1213     X509_STORE_CTX cert_ctx;
1214     STACK_OF(X509) *intermediateCAs = NULL;
1215     STACK_OF(X509_CRL) *revoked = NULL;
1216     STACK_OF(X509) *verified_chain = NULL;
1217     ASN1_OBJECT *oid = NULL;
1218     krb5_external_principal_identifier **krb5_verified_chain = NULL;
1219     krb5_data *authz = NULL;
1220     char buf[DN_BUF_LEN];
1221 
1222 #ifdef DEBUG_ASN1
1223     print_buffer_bin(signed_data, signed_data_len,
1224                      "/tmp/client_received_pkcs7_signeddata");
1225 #endif
1226 
1227     /* Do this early enough to create the shadow OID for pkcs7-data if needed */
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     int nid;
3131 
3132     switch (pkcs7_type) {
3133         case CMS_SIGN_CLIENT:
3134             return cryptoctx->id_pkinit_authData;
3135         case CMS_SIGN_DRAFT9:
3136             /*
3137              * Delay creating this OID until we know we need it.
3138              * It shadows an existing OpenSSL oid.  If it
3139              * is created too early, it breaks things like
3140              * the use of pkcs12 (which uses pkcs7 structures).
3141              * We need this shadow version because our code
3142              * depends on the "other" type to be unknown to the
3143              * OpenSSL code.
3144              */ 
3145             if (cryptoctx->id_pkinit_authData9 == NULL) {
3146                 pkiDebug("%s: Creating shadow instance of pkcs7-data oid\n",
3147                          __FUNCTION__);
3148                 nid = OBJ_create("1.2.840.113549.1.7.1", "id-pkcs7-data",
3149                                  "PKCS7 data");
3150                 if (nid == NID_undef)
3151                     return NULL;
3152                 cryptoctx->id_pkinit_authData9 = OBJ_nid2obj(nid);
3153             }
3154             return cryptoctx->id_pkinit_authData9;
3155         case CMS_SIGN_SERVER:
3156             return cryptoctx->id_pkinit_DHKeyData;
3157         case CMS_ENVEL_SERVER:
3158             return cryptoctx->id_pkinit_rkeyData;
3159         default:
3160             return NULL;
3161     }
3162 
3163 }
3164 
3165 #ifdef LONGHORN_BETA_COMPAT
3166 #if 0
3167 /*
3168  * This is a version that worked with Longhorn Beta 3.
3169  */
3170 static int
3171 wrap_signeddata(unsigned char *data, unsigned int data_len,
3172                 unsigned char **out, unsigned int *out_len,
3173                 int is_longhorn_server)
3174 {
3175 
3176     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3177     ASN1_OBJECT *oid = NULL;
3178     unsigned char *p = NULL;
3179 
3180     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3181              __FUNCTION__, is_longhorn_server);
3182 
3183     /* Get length to wrap the original data with SEQUENCE tag */
3184     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3185 
3186     if (is_longhorn_server == 0) {
3187         /* Add the signedData OID and adjust lengths */
3188         oid = OBJ_nid2obj(NID_pkcs7_signed);
3189         oid_len = i2d_ASN1_OBJECT(oid, NULL);
3190 
3191         tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3192     }
3193 
3194     p = *out = (unsigned char *)malloc(tot_len);
3195     if (p == NULL) return -1;
3196 
3197     if (is_longhorn_server == 0) {
3198         ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3199                         V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3200 
3201         i2d_ASN1_OBJECT(oid, &p);
3202 
3203         ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3204     } else {
3205         ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3206     }
3207     memcpy(p, data, data_len);
3208 
3209     *out_len = tot_len;
3210 
3211     return 0;
3212 }
3213 #else
3214 /*
3215  * This is a version that works with a patched Longhorn KDC.
3216  * (Which should match SP1 ??).
3217  */
3218 static int
3219 wrap_signeddata(unsigned char *data, unsigned int data_len,
3220                unsigned char **out, unsigned int *out_len,
3221                int is_longhorn_server)
3222 {
3223 
3224     unsigned int oid_len = 0, tot_len = 0, wrap_len = 0, tag_len = 0;
3225     ASN1_OBJECT *oid = NULL;
3226     unsigned char *p = NULL;
3227 
3228     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3229              __FUNCTION__, is_longhorn_server);
3230 
3231     /* New longhorn is missing another sequence */
3232     if (is_longhorn_server == 1)
3233        wrap_len = ASN1_object_size(1, (int)(data_len), V_ASN1_SEQUENCE);
3234     else
3235        wrap_len = data_len;
3236 
3237     /* Get length to wrap the original data with SEQUENCE tag */
3238     tag_len = ASN1_object_size(1, (int)wrap_len, V_ASN1_SEQUENCE);
3239 
3240     /* Always add oid */
3241     oid = OBJ_nid2obj(NID_pkcs7_signed);
3242     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3243     oid_len += tag_len;
3244 
3245     tot_len = ASN1_object_size(1, (int)(oid_len), V_ASN1_SEQUENCE);
3246 
3247     p = *out = (unsigned char *)malloc(tot_len);
3248     if (p == NULL)
3249        return -1;
3250 
3251     ASN1_put_object(&p, 1, (int)(oid_len),
3252                     V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3253 
3254     i2d_ASN1_OBJECT(oid, &p);
3255 
3256     ASN1_put_object(&p, 1, (int)wrap_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3257 
3258     /* Wrap in extra seq tag */
3259     if (is_longhorn_server == 1) {
3260        ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3261     }
3262     (void) memcpy(p, data, data_len);
3263 
3264     *out_len = tot_len;
3265 
3266     return 0;
3267 }
3268 
3269 #endif
3270 #else
3271 static int
3272 wrap_signeddata(unsigned char *data, unsigned int data_len,
3273                 unsigned char **out, unsigned int *out_len)
3274 {
3275 
3276     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3277     ASN1_OBJECT *oid = NULL;
3278     unsigned char *p = NULL;
3279 
3280     /* Get length to wrap the original data with SEQUENCE tag */
3281     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3282 
3283     /* Add the signedData OID and adjust lengths */
3284     oid = OBJ_nid2obj(NID_pkcs7_signed);
3285     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3286 
3287     tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3288 
3289     p = *out = (unsigned char *)malloc(tot_len);
3290     if (p == NULL) return -1;
3291 
3292     ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3293                     V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3294 
3295     i2d_ASN1_OBJECT(oid, &p);
3296 
3297     ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3298     (void) memcpy(p, data, data_len);
3299 
3300     *out_len = tot_len;
3301 
3302     return 0;
3303 }
3304 #endif
3305 
3306 static int
3307 prepare_enc_data(unsigned char *indata,
3308                  int indata_len,
3309                  unsigned char **outdata,
3310                  int *outdata_len)
3311 {
3312     /* Solaris Kerberos */
3313     ASN1_const_CTX c;
3314     long length = indata_len;
3315     int Ttag, Tclass;
3316     long Tlen;
3317 
3318     c.pp = (const unsigned char **)&indata;
3319     c.q = *(const unsigned char **)&indata;
3320     c.error = ERR_R_NESTED_ASN1_ERROR;
3321     c.p= *(const unsigned char **)&indata;
3322     c.max = (length == 0)?0:(c.p+length);
3323 
3324     asn1_GetSequence(&c,&length);
3325 
3326     ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
3327     c.p += Tlen;
3328     ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
3329 
3330     asn1_const_Finish(&c);
3331 
3332     *outdata = (unsigned char *)malloc((size_t)Tlen);
3333     /* Solaris Kerberos */
3334     if (outdata == NULL)
3335         return ENOMEM;
3336     
3337     (void) memcpy(*outdata, c.p, (size_t)Tlen);
3338     *outdata_len = Tlen;
3339 
3340     return 0;
3341 }
3342 
3343 #ifndef WITHOUT_PKCS11
3344 static void *
3345 pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
3346 {
3347     void *handle;
3348     CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
3349 
3350     pkiDebug("loading module \"%s\"... ", modname);
3351     /* Solaris Kerberos */
3352     handle = dlopen(modname, RTLD_NOW | RTLD_GROUP);
3353     if (handle == NULL) {
3354         pkiDebug("not found\n");
3355         return NULL;
3356     }
3357     getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
3358     if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
3359         (void) dlclose(handle);
3360         pkiDebug("failed\n");
3361         return NULL;
3362     }
3363     pkiDebug("ok\n");
3364     return handle;
3365 }
3366 
3367 static CK_RV
3368 pkinit_C_UnloadModule(void *handle)
3369 {
3370     /* Solaris Kerberos */
3371     if (dlclose(handle) != 0)
3372         return CKR_GENERAL_ERROR;
3373 
3374     return CKR_OK;
3375 }
3376 
3377 /*
3378  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3379  * code.
3380  *
3381  * labelstr will be C string containing token label with trailing white space
3382  * removed.
3383  */
3384 static void
3385 trim_token_label(CK_TOKEN_INFO *tinfo, char *labelstr, unsigned int labelstr_len)
3386 {
3387     int i;
3388 
3389     assert(labelstr_len > sizeof (tinfo->label));
3390     /*
3391      * \0 terminate labelstr in case the last char in the token label is
3392      * non-whitespace
3393      */
3394     labelstr[sizeof (tinfo->label)] = '\0';
3395     (void) memcpy(labelstr, (char *) tinfo->label, sizeof (tinfo->label));
3396 
3397     /* init i so terminating \0 is skipped */
3398     for (i = sizeof (tinfo->label) - 1; i >= 0; i--) {
3399         if (labelstr[i] == ' ')
3400             labelstr[i] = '\0';
3401         else
3402             break;
3403     }
3404 }
3405 
3406 /*
3407  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3408  * code.
3409  */
3410 static krb5_error_code
3411 pkinit_prompt_user(krb5_context context,
3412                    pkinit_identity_crypto_context cctx,
3413                    krb5_data *reply,
3414                    char *prompt,
3415                    int hidden)
3416 {
3417     krb5_error_code r;
3418     krb5_prompt kprompt;
3419     krb5_prompt_type prompt_type;
3420 
3421     if (cctx->prompter == NULL)
3422         return (EINVAL);
3423 
3424     kprompt.prompt = prompt;
3425     kprompt.hidden = hidden;
3426     kprompt.reply = reply;
3427     /*
3428      * Note, assuming this type for now, may need to be passed in in the future.
3429      */
3430     prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
3431 
3432     /* PROMPTER_INVOCATION */
3433     k5int_set_prompt_types(context, &prompt_type);
3434     r = (*cctx->prompter)(context, cctx->prompter_data,
3435                           NULL, NULL, 1, &kprompt);
3436     k5int_set_prompt_types(context, NULL);
3437     return (r);
3438 }
3439 
3440 /*
3441  * Solaris Kerberos: this function was changed to support a PIN being passed
3442  * in.  If that is the case the user will not be prompted for their PIN.
3443  */
3444 static krb5_error_code
3445 pkinit_login(krb5_context context,
3446              pkinit_identity_crypto_context id_cryptoctx,
3447              CK_TOKEN_INFO *tip)
3448 {
3449     krb5_data rdat;
3450     char *prompt;
3451     int prompt_len;
3452     int r = 0;
3453 
3454     if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
3455         rdat.data = NULL;
3456         rdat.length = 0;
3457     } else if (id_cryptoctx->PIN != NULL) {
3458         if ((rdat.data = strdup(id_cryptoctx->PIN)) == NULL)
3459             return (ENOMEM);
3460         /*
3461          * Don't include NULL string terminator in length calculation as this
3462          * PIN is passed to the C_Login function and only the text chars should
3463          * be considered to be the PIN.
3464          */
3465         rdat.length = strlen(id_cryptoctx->PIN);
3466     } else {
3467         /* Solaris Kerberos - trim token label */
3468         char tmplabel[sizeof (tip->label) + 1];
3469 
3470         if (!id_cryptoctx->prompter) {
3471             pkiDebug("pkinit_login: id_cryptoctx->prompter is NULL\n");
3472             /* Solaris Kerberos: Improved error messages */
3473             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3474                 gettext("Failed to log into token: prompter function is NULL"));
3475             return (KRB5KDC_ERR_PREAUTH_FAILED);
3476         }
3477         /* Solaris Kerberos - Changes for gettext() */
3478         prompt_len = sizeof (tip->label) + 256;
3479         if ((prompt = (char *) malloc(prompt_len)) == NULL)
3480             return ENOMEM;
3481 
3482         /* Solaris Kerberos - trim token label which can be padded with space */
3483         trim_token_label(tip, tmplabel, sizeof (tmplabel));
3484         (void) snprintf(prompt, prompt_len, gettext("%s PIN"), tmplabel);
3485 
3486         /* Solaris Kerberos */
3487         if (tip->flags & CKF_USER_PIN_LOCKED)
3488             (void) strlcat(prompt, gettext(" (Warning: PIN locked)"), prompt_len);
3489         else if (tip->flags & CKF_USER_PIN_FINAL_TRY)
3490             (void) strlcat(prompt, gettext(" (Warning: PIN final try)"), prompt_len);
3491         else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
3492             (void) strlcat(prompt, gettext(" (Warning: PIN count low)"), prompt_len);
3493         rdat.data = malloc(tip->ulMaxPinLen + 2);
3494         rdat.length = tip->ulMaxPinLen + 1;
3495         /*
3496          * Note that the prompter function will set rdat.length such that the
3497          * NULL terminator is not included
3498          */
3499         /* PROMPTER_INVOCATION */
3500         r = pkinit_prompt_user(context, id_cryptoctx, &rdat, prompt, 1);
3501         free(prompt);
3502     }
3503 
3504     if (r == 0) {
3505         r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
3506                 (u_char *) rdat.data, rdat.length);
3507 
3508         if (r != CKR_OK) {
3509             pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r));
3510             /* Solaris Kerberos: Improved error messages */
3511             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3512                 gettext("Failed to log into token: %s"),
3513                 pkinit_pkcs11_code_to_text(r));
3514             r = KRB5KDC_ERR_PREAUTH_FAILED;
3515         } else {
3516             /* Solaris Kerberos: only need to login once */
3517             id_cryptoctx->p11flags |= C_LOGIN_DONE;
3518         }
3519     }
3520     if (rdat.data) {
3521         (void) memset(rdat.data, 0, rdat.length);
3522         free(rdat.data);
3523     }
3524 
3525     return (r);
3526 }
3527 
3528 /*
3529  * Solaris Kerberos: added these structs in support of prompting user for
3530  * missing token.
3531  */
3532 struct _token_entry {
3533     CK_SLOT_ID slotID;
3534     CK_SESSION_HANDLE session;
3535     CK_TOKEN_INFO token_info;
3536 };
3537 struct _token_choices {
3538     unsigned int numtokens;
3539     struct _token_entry *token_array;
3540 };
3541 
3542 
3543 /*
3544  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3545  * code.
3546  */
3547 static krb5_error_code
3548 pkinit_prompt_token(krb5_context context,
3549                     pkinit_identity_crypto_context cctx)
3550 {
3551     char tmpbuf[4];
3552     krb5_data reply;
3553     char *token_prompt = gettext("If you have a smartcard insert it now. "
3554                                  "Press enter to continue");
3555 
3556     reply.data = tmpbuf;
3557     reply.length = sizeof(tmpbuf);
3558 
3559     /* note, don't care about the reply */
3560     return (pkinit_prompt_user(context, cctx, &reply, token_prompt, 0));
3561 }
3562 
3563 /*
3564  * Solaris Kerberos: new defines for prompting support.
3565  */
3566 #define CHOOSE_THIS_TOKEN 0
3567 #define CHOOSE_RESCAN 1
3568 #define CHOOSE_SKIP 2
3569 #define CHOOSE_SEE_NEXT 3
3570 
3571 #define RESCAN_TOKENS -1
3572 #define SKIP_TOKENS -2
3573 
3574 /*
3575  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3576  * code.
3577  *
3578  * This prompts to user for various choices regarding a token to use.  Note
3579  * that if there is no error, choice will be set to one of:
3580  * - the token_choices->token_array entry
3581  * - RESCAN_TOKENS
3582  * - SKIP_TOKENS
3583  */
3584 static int
3585 pkinit_choose_tokens(krb5_context context,
3586                      pkinit_identity_crypto_context cctx,
3587                      struct _token_choices *token_choices,
3588                      int *choice)
3589 {
3590     krb5_error_code r;
3591     /*
3592      * Assuming that PAM_MAX_MSG_SIZE is a reasonable restriction. Note that -
3593      * 2 is to account for the fact that a krb prompter to PAM conv bridge will
3594      * add ": ".
3595      */
3596     char prompt[PAM_MAX_MSG_SIZE - 2];
3597     char tmpbuf[4];
3598     char tmplabel[sizeof (token_choices->token_array->token_info.label) + 1];
3599     krb5_data reply;
3600     int i, num_used, tmpchoice;
3601 
3602     assert(token_choices != NULL);
3603     assert(choice != NULL);
3604 
3605     /* Create the menu prompt */
3606 
3607     /* only need to do this once before the for loop */
3608     reply.data = tmpbuf;
3609 
3610     for (i = 0; i < token_choices->numtokens; i++) {
3611 
3612         trim_token_label(&token_choices->token_array[i].token_info, tmplabel,
3613                          sizeof (tmplabel));
3614 
3615         if (i == (token_choices->numtokens - 1)) {
3616             /* no more smartcards/tokens */
3617             if ((num_used = snprintf(prompt, sizeof (prompt),
3618                                      "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n",
3619                                      /*
3620                                       * TRANSLATION_NOTE: Translations of the
3621                                       * following 5 strings must not exceed 450
3622                                       * bytes total.
3623                                       */
3624                                      gettext("Select one of the following and press enter:"),
3625                                      CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3626                                      gettext("in slot"), token_choices->token_array[i].slotID,
3627                                      CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3628                                      CHOOSE_SKIP, gettext("Skip smartcard authentication")))
3629                 >= sizeof (prompt)) {
3630                 pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3631                          " sizeof prompt: %d\n", num_used, sizeof (prompt));
3632                 krb5_set_error_message(context, EINVAL,
3633                                gettext("In pkinit_choose_tokens: prompt size"
3634                                       " %d exceeds prompt buffer size %d"),
3635                                num_used, sizeof(prompt));
3636                 (void) snprintf(prompt, sizeof (prompt), "%s",
3637                                 gettext("Error: PKINIT prompt message is too large for buffer, "
3638                                         "please alert the system administrator. Press enter to "
3639                                         "continue"));
3640                 reply.length = sizeof(tmpbuf);
3641                 if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3642                     return (r);
3643                 return (EINVAL);
3644             }
3645         } else {
3646             if ((num_used = snprintf(prompt, sizeof (prompt),
3647                                      "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n%d: %s\n",
3648                                      /*
3649                                       * TRANSLATION_NOTE: Translations of the
3650                                       * following 6 strings must not exceed 445
3651                                       * bytes total.
3652                                       */
3653                                      gettext("Select one of the following and press enter:"),
3654                                      CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3655                                      gettext("in slot"), token_choices->token_array[i].slotID,
3656                                      CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3657                                      CHOOSE_SKIP, gettext("Skip smartcard authentication"),
3658                                      CHOOSE_SEE_NEXT, gettext("See next smartcard")))
3659                 >= sizeof (prompt)) {
3660 
3661                 pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3662                          " sizeof prompt: %d\n", num_used, sizeof (prompt));
3663                 krb5_set_error_message(context, EINVAL,
3664                                        gettext("In pkinit_choose_tokens: prompt size"
3665                                                " %d exceeds prompt buffer size %d"),
3666                                        num_used, sizeof(prompt));
3667                 (void) snprintf(prompt, sizeof (prompt), "%s",
3668                                 gettext("Error: PKINIT prompt message is too large for buffer, "
3669                                         "please alert the system administrator. Press enter to "
3670                                         "continue"));
3671                 reply.length = sizeof(tmpbuf);
3672                 if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3673                     return (r);
3674                 return (EINVAL);
3675             }
3676         }
3677 
3678         /*
3679          * reply.length needs to be reset to length of tmpbuf before calling
3680          * prompter
3681          */
3682         reply.length = sizeof(tmpbuf);
3683         if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3684             return (r);
3685 
3686         if (reply.length == 0) {
3687             return (EINVAL);
3688         } else {
3689             char *cp = reply.data;
3690             /* reply better be digits */
3691             while (*cp != NULL) {
3692                 if (!isdigit(*cp++))
3693                     return (EINVAL);
3694             }
3695             errno = 0;
3696             tmpchoice = (int) strtol(reply.data, (char **)NULL, 10);
3697             if (errno != 0)
3698                 return (errno);
3699         }
3700 
3701         switch (tmpchoice) {
3702         case CHOOSE_THIS_TOKEN:
3703             *choice = i; /* chosen entry of token_choices->token_array */
3704             return (0);
3705         case CHOOSE_RESCAN:
3706             *choice = RESCAN_TOKENS; /* rescan for new smartcard */
3707             return (0);
3708         case CHOOSE_SKIP:
3709             *choice = SKIP_TOKENS; /* skip smartcard auth */
3710             return (0);
3711         case CHOOSE_SEE_NEXT: /* see next smartcard */
3712             continue;
3713         default:
3714             return (EINVAL);
3715         }
3716     }
3717 
3718     return (0);
3719 }
3720 
3721 /*
3722  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3723  * code.
3724  *
3725  * Note, this isn't the best solution to providing a function to check the
3726  * certs in a token however I wanted to avoid rewriting a bunch of code so I
3727  * settled for some duplication of processing.
3728  */
3729 static krb5_error_code
3730 check_load_certs(krb5_context context,
3731             CK_SESSION_HANDLE session,
3732             pkinit_plg_crypto_context plg_cryptoctx,
3733             pkinit_req_crypto_context req_cryptoctx,
3734             pkinit_identity_crypto_context id_cryptoctx,
3735             krb5_principal princ,
3736             int do_matching,
3737             int load_cert)
3738 {
3739     CK_OBJECT_CLASS cls;
3740     CK_OBJECT_HANDLE obj;
3741     CK_ATTRIBUTE attrs[4];
3742     CK_ULONG count;
3743     CK_CERTIFICATE_TYPE certtype;
3744     CK_BYTE_PTR cert = NULL, cert_id = NULL;
3745     const unsigned char *cp;
3746     int i, r;
3747     unsigned int nattrs;
3748     X509 *x = NULL;
3749 
3750     cls = CKO_CERTIFICATE;
3751     attrs[0].type = CKA_CLASS;
3752     attrs[0].pValue = &cls;
3753     attrs[0].ulValueLen = sizeof cls;
3754 
3755     certtype = CKC_X_509;
3756     attrs[1].type = CKA_CERTIFICATE_TYPE;
3757     attrs[1].pValue = &certtype;
3758     attrs[1].ulValueLen = sizeof certtype;
3759 
3760     nattrs = 2;
3761 
3762     /* If a cert id and/or label were given, use them too */
3763     if (id_cryptoctx->cert_id_len > 0) {
3764         attrs[nattrs].type = CKA_ID;
3765         attrs[nattrs].pValue = id_cryptoctx->cert_id;
3766         attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
3767         nattrs++;
3768     }
3769     if (id_cryptoctx->cert_label != NULL) {
3770         attrs[nattrs].type = CKA_LABEL;
3771         attrs[nattrs].pValue = id_cryptoctx->cert_label;
3772         attrs[nattrs].ulValueLen = strlen(id_cryptoctx->cert_label);
3773         nattrs++;
3774     }
3775 
3776     r = id_cryptoctx->p11->C_FindObjectsInit(session, attrs, nattrs);
3777     if (r != CKR_OK) {
3778         pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r));
3779         krb5_set_error_message(context, EINVAL,
3780                                gettext("PKCS11 error from C_FindObjectsInit: %s"),
3781                                pkinit_pkcs11_code_to_text(r));
3782         r = EINVAL;
3783         goto out;
3784     }
3785 
3786     for (i = 0; ; i++) {
3787         if (i >= MAX_CREDS_ALLOWED) {
3788             r = EINVAL;
3789             goto out;
3790         }
3791 
3792         /* Look for x.509 cert */
3793         /* Solaris Kerberos */
3794         if ((r = id_cryptoctx->p11->C_FindObjects(session, &obj, 1, &count))
3795             != CKR_OK || count == 0) {
3796             id_cryptoctx->creds[i] = NULL;
3797             break;
3798         }
3799 
3800         /* Get cert and id len */
3801         attrs[0].type = CKA_VALUE;
3802         attrs[0].pValue = NULL;
3803         attrs[0].ulValueLen = 0;
3804 
3805         attrs[1].type = CKA_ID;
3806         attrs[1].pValue = NULL;
3807         attrs[1].ulValueLen = 0;
3808 
3809         if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
3810                                                         obj,
3811                                                         attrs,
3812                                                         2)) != CKR_OK &&
3813             r != CKR_BUFFER_TOO_SMALL) {
3814             pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
3815             krb5_set_error_message(context, EINVAL,
3816                                    gettext("Error from PKCS11 C_GetAttributeValue: %s"),
3817                                    pkinit_pkcs11_code_to_text(r));
3818             r = EINVAL;
3819             goto out;
3820         }
3821         cert = malloc((size_t) attrs[0].ulValueLen + 1);
3822         if (cert == NULL) {
3823             r = ENOMEM;
3824             goto out;
3825         }
3826         cert_id = malloc((size_t) attrs[1].ulValueLen + 1);
3827         if (cert_id == NULL) {
3828             r = ENOMEM;
3829             goto out;
3830         }
3831 
3832         /* Read the cert and id off the card */
3833 
3834         attrs[0].type = CKA_VALUE;
3835         attrs[0].pValue = cert;
3836 
3837         attrs[1].type = CKA_ID;
3838         attrs[1].pValue = cert_id;
3839 
3840         if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
3841                 obj, attrs, 2)) != CKR_OK) {
3842             pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
3843             krb5_set_error_message(context, EINVAL,
3844                                    gettext("Error from PKCS11 C_GetAttributeValue: %s"),
3845                                    pkinit_pkcs11_code_to_text(r));
3846             r = EINVAL;
3847             goto out;
3848         }
3849 
3850         pkiDebug("cert %d size %d id %d idlen %d\n", i,
3851             (int) attrs[0].ulValueLen, (int) cert_id[0],
3852             (int) attrs[1].ulValueLen);
3853 
3854         cp = (unsigned char *) cert;
3855         x = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
3856         if (x == NULL) {
3857             r = EINVAL;
3858             goto out;
3859         }
3860 
3861         id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
3862         if (id_cryptoctx->creds[i] == NULL) {
3863             r = ENOMEM;
3864             goto out;
3865         }
3866         id_cryptoctx->creds[i]->cert = x;
3867         id_cryptoctx->creds[i]->key = NULL;
3868         id_cryptoctx->creds[i]->cert_id = cert_id;
3869         cert_id = NULL;
3870         id_cryptoctx->creds[i]->cert_id_len = attrs[1].ulValueLen;
3871         free(cert);
3872         cert = NULL;
3873     }
3874     id_cryptoctx->p11->C_FindObjectsFinal(session);
3875 
3876     if (id_cryptoctx->creds[0] == NULL || id_cryptoctx->creds[0]->cert == NULL) {
3877         r = ENOENT;
3878     } else if (do_matching){
3879         /*
3880          * Do not let pkinit_cert_matching set the primary cert in id_cryptoctx
3881          * as this will be done later.
3882          */
3883         r = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
3884                                  id_cryptoctx, princ, FALSE);
3885     }
3886 
3887 out:
3888     if ((r != 0 || !load_cert) &&
3889         id_cryptoctx->creds[0] != NULL &&
3890         id_cryptoctx->creds[0]->cert != NULL) {
3891         /*
3892          * If there's an error or load_cert isn't 1 free all the certs loaded
3893          * onto id_cryptoctx.
3894          */
3895         (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
3896                                      id_cryptoctx);
3897     }
3898 
3899     if (cert)
3900         free(cert);
3901 
3902     if (cert_id)
3903         free(cert_id);
3904     
3905     return (r);
3906 }
3907 
3908 /*
3909  * Solaris Kerberos: this function has been significantly modified to prompt
3910  * the user in certain cases so defer to this version when resyncing MIT code.
3911  *
3912  * pkinit_open_session now does several things including prompting the user if
3913  * do_matching is set which indicates the code is executing in a client
3914  * context.  This function fills out a pkinit_identity_crypto_context with a
3915  * set of certs and a open session if a token can be found that matches all
3916  * supplied criteria.  If no token is found then the user is prompted one time
3917  * to insert their token.  If there is more than one token that matches all
3918  * client criteria the user is prompted to make a choice if in client context.
3919  * If do_matching is false (KDC context) then the first token matching all
3920  * server criteria is chosen.
3921  */
3922 static krb5_error_code
3923 pkinit_open_session(krb5_context context,
3924                     pkinit_plg_crypto_context plg_cryptoctx,
3925                     pkinit_req_crypto_context req_cryptoctx,
3926                     pkinit_identity_crypto_context cctx,
3927                     krb5_principal princ,
3928                     int do_matching)
3929 {
3930     int i, r;
3931     CK_ULONG count = 0;
3932     CK_SLOT_ID_PTR slotlist = NULL, tmpslotlist = NULL;
3933     CK_TOKEN_INFO tinfo;
3934     krb5_boolean tokenmatch = FALSE;
3935     CK_SESSION_HANDLE tmpsession = NULL;
3936     struct _token_choices token_choices;
3937     int choice = 0;
3938 
3939     if (cctx->session != CK_INVALID_HANDLE)
3940         return 0; /* session already open */
3941 
3942     /* Load module */
3943     if (cctx->p11_module == NULL) {
3944         cctx->p11_module =
3945             pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11);
3946         if (cctx->p11_module == NULL)
3947             return KRB5KDC_ERR_PREAUTH_FAILED;
3948     }
3949 
3950     /* Init */
3951     /* Solaris Kerberos: Don't fail if cryptoki is already initialized */
3952     r = cctx->p11->C_Initialize(NULL);
3953     if (r != CKR_OK && r != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
3954         pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r));
3955         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3956                                gettext("Error from PKCS11 C_Initialize: %s"),
3957                                pkinit_pkcs11_code_to_text(r));
3958         return KRB5KDC_ERR_PREAUTH_FAILED;
3959     }
3960 
3961     (void) memset(&token_choices, 0, sizeof(token_choices));
3962 
3963     /*
3964      * Solaris Kerberos:
3965      * If C_Initialize was already called by the process before the pkinit
3966      * module was loaded then record that fact.
3967      * "finalize_pkcs11" is used by pkinit_fini_pkcs11 to determine whether
3968      * or not C_Finalize() should be called. 
3969      */
3970      cctx->finalize_pkcs11 =
3971         (r == CKR_CRYPTOKI_ALREADY_INITIALIZED ? FALSE : TRUE);
3972     /*
3973      * First make sure that is an applicable slot otherwise fail.
3974      *
3975      * Start by getting a count of all slots with or without tokens.
3976      */
3977 
3978     if ((r = cctx->p11->C_GetSlotList(FALSE, NULL, &count)) != CKR_OK) {
3979         pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
3980         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3981             gettext("Error trying to get PKCS11 slot list: %s"),
3982             pkinit_pkcs11_code_to_text(r));
3983         r = KRB5KDC_ERR_PREAUTH_FAILED;
3984         goto out;
3985     }
3986 
3987     if (count == 0) {
3988         /* There are no slots so bail */
3989         r = KRB5KDC_ERR_PREAUTH_FAILED;
3990         krb5_set_error_message(context, r,
3991                                gettext("No PKCS11 slots found"));
3992         pkiDebug("pkinit_open_session: no slots, count: %d\n", count);
3993         goto out;
3994     } else if (cctx->slotid != PK_NOSLOT) {
3995         /* See if any of the slots match the specified slotID */
3996         tmpslotlist = malloc(count * sizeof (CK_SLOT_ID));
3997         if (tmpslotlist == NULL) {
3998             krb5_set_error_message(context, ENOMEM,
3999                                    gettext("Memory allocation error:"));
4000             r = KRB5KDC_ERR_PREAUTH_FAILED;
4001             goto out;
4002         }
4003         if ((r = cctx->p11->C_GetSlotList(FALSE, tmpslotlist, &count)) != CKR_OK) {
4004             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4005                                    gettext("Error trying to get PKCS11 slot list: %s"),
4006                                    pkinit_pkcs11_code_to_text(r));
4007             pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4008             r = KRB5KDC_ERR_PREAUTH_FAILED;
4009             goto out;
4010         }
4011 
4012         for (i = 0; i < count && cctx->slotid != tmpslotlist[i]; i++)
4013             continue;
4014 
4015         if (i >= count) {
4016             /* no slots match */
4017             r = KRB5KDC_ERR_PREAUTH_FAILED;
4018             krb5_set_error_message(context, r,
4019                                    gettext("Requested PKCS11 slot ID %d not found"),
4020                                    cctx->slotid);
4021             pkiDebug("open_session: no matching slot found for slotID %d\n",
4022                      cctx->slotid);
4023             goto out;
4024         }
4025     }
4026     
4027 tryagain:
4028     /* get count of slots that have tokens */
4029     if ((r = cctx->p11->C_GetSlotList(TRUE, NULL, &count)) != CKR_OK) {
4030         pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4031         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4032                                gettext("Error trying to get PKCS11 slot list: %s"),
4033                                pkinit_pkcs11_code_to_text(r));
4034         r = KRB5KDC_ERR_PREAUTH_FAILED;
4035         goto out;
4036     }
4037 
4038     if (count == 0) {
4039         /*
4040          * Note, never prompt if !do_matching as this implies KDC side
4041          * processing
4042          */
4043         if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4044             /* found slot(s) but no token so prompt and try again */
4045             if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4046                 cctx->p11flags |= C_PROMPTED_USER;
4047                 goto tryagain;
4048             } else {
4049                 pkiDebug("open_session: prompt for token/smart card failed\n");
4050                 krb5_set_error_message(context, r,
4051                                        gettext("Prompt for token/smart card failed"));
4052                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4053                 goto out;
4054             }
4055 
4056         } else {
4057             /* already prompted once so bailing */
4058             r = KRB5KDC_ERR_PREAUTH_FAILED;
4059             krb5_set_error_message(context, r,
4060                                    gettext("No smart card tokens found"));
4061             pkiDebug("pkinit_open_session: no token, already prompted\n");
4062             goto out;
4063         }
4064     }
4065 
4066     if (slotlist != NULL)
4067         free(slotlist);
4068  
4069     slotlist = malloc(count * sizeof (CK_SLOT_ID));
4070     if (slotlist == NULL) {
4071         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4072                                gettext("Memory allocation error"));
4073         r = KRB5KDC_ERR_PREAUTH_FAILED;
4074         goto out;
4075     }
4076     /*
4077      * Solaris Kerberos: get list of PKCS11 slotid's that have tokens.
4078      */
4079     if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
4080         krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4081                                gettext("Error trying to get PKCS11 slot list: %s"),
4082                                pkinit_pkcs11_code_to_text(r));
4083         pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4084         r = KRB5KDC_ERR_PREAUTH_FAILED;
4085         goto out;
4086     }
4087 
4088     token_choices.numtokens = 0;
4089     token_choices.token_array = malloc(count * sizeof (*token_choices.token_array));
4090     if (token_choices.token_array == NULL) {
4091         r = KRB5KDC_ERR_PREAUTH_FAILED;
4092         krb5_set_error_message(context, r,
4093                                gettext("Memory allocation error"));
4094         goto out;
4095     }
4096 
4097     /* examine all the tokens */
4098     for (i = 0; i < count; i++) {
4099         /*
4100          * Solaris Kerberos: if a slotid was specified skip slots that don't
4101          * match.
4102          */
4103         if (cctx->slotid != PK_NOSLOT && cctx->slotid != slotlist[i])
4104             continue;
4105 
4106         /* Open session */
4107         if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
4108                                           NULL, NULL, &tmpsession)) != CKR_OK) {
4109             pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r));
4110             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4111                                    gettext("Error trying to open PKCS11 session: %s"),
4112                                    pkinit_pkcs11_code_to_text(r));
4113             r = KRB5KDC_ERR_PREAUTH_FAILED;
4114             goto out;
4115         }
4116 
4117         /* Get token info */
4118         if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) {
4119             pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r));
4120             krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4121                                    gettext("Error trying to read PKCS11 token: %s"),
4122                                    pkinit_pkcs11_code_to_text(r));
4123             r = KRB5KDC_ERR_PREAUTH_FAILED;
4124             cctx->p11->C_CloseSession(tmpsession);
4125             goto out;
4126         }
4127 
4128         if (cctx->token_label == NULL) {
4129             /*
4130              * If the token doesn't require login to examine the certs then
4131              * let's check the certs out to see if any match the criteria if
4132              * any.
4133              */
4134             if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4135                 /*
4136                  * It's okay to check the certs if we don't have to login but
4137                  * don't load the certs onto cctx at this point, this will be
4138                  * done later in this function for the chosen token.
4139                  */
4140                 if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4141                                           req_cryptoctx, cctx, princ,
4142                                           do_matching, 0)) == 0) {
4143                     tokenmatch = TRUE;
4144                 } else if (r != ENOENT){
4145                     r = KRB5KDC_ERR_PREAUTH_FAILED;
4146                     cctx->p11->C_CloseSession(tmpsession);
4147                     goto out;
4148                 } else {
4149                     /* ignore ENOENT here */
4150                     r = 0;
4151                 }
4152             } else {
4153                 tokenmatch = TRUE;
4154             }
4155         } else {
4156             /* + 1 so tokenlabelstr can be \0 terminated */
4157             char tokenlabelstr[sizeof (tinfo.label) + 1];
4158 
4159             /*
4160              * Convert token label into C string with trailing white space
4161              * trimmed.
4162              */
4163             trim_token_label(&tinfo, tokenlabelstr, sizeof (tokenlabelstr));
4164 
4165             pkiDebug("open_session: slotid %d token found: \"%s\", "
4166                      "cctx->token_label: \"%s\"\n",
4167                      slotlist[i], tokenlabelstr, (char *) cctx->token_label);
4168 
4169             if (!strcmp(cctx->token_label, tokenlabelstr)) {
4170                 if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4171                     /*
4172                      * It's okay to check the certs if we don't have to login but
4173                      * don't load the certs onto cctx at this point, this will be
4174                      * done later in this function for the chosen token.
4175                      */
4176                     if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4177                                               req_cryptoctx, cctx, princ,
4178                                               do_matching, 0)) == 0) {
4179                         tokenmatch = TRUE;
4180                     } else if (r != ENOENT){
4181                         r = KRB5KDC_ERR_PREAUTH_FAILED;
4182                         cctx->p11->C_CloseSession(tmpsession);
4183                         goto out;
4184                     } else {
4185                         /* ignore ENOENT here */
4186                         r = 0;
4187                     }
4188                 } else {
4189                     tokenmatch = TRUE;
4190                 }
4191             }
4192         }
4193 
4194         if (tokenmatch == TRUE) {
4195             /* add the token to token_choices.token_array */
4196             token_choices.token_array[token_choices.numtokens].slotID = slotlist[i];
4197             token_choices.token_array[token_choices.numtokens].session = tmpsession;
4198             token_choices.token_array[token_choices.numtokens].token_info = tinfo;
4199             token_choices.numtokens++;
4200             /* !do_matching implies we take the first matching token */
4201             if (!do_matching)
4202                 break;
4203             else
4204                 tokenmatch = FALSE;
4205         } else {
4206             cctx->p11->C_CloseSession(tmpsession);
4207         }
4208     }
4209 
4210     if (token_choices.numtokens == 0) {
4211         /*
4212          * Solaris Kerberos: prompt for token one time if there was no token
4213          * and do_matching is 1 (see earlier comment about do_matching).
4214          */
4215         if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4216             if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4217                 cctx->p11flags |= C_PROMPTED_USER;
4218                 goto tryagain;
4219             } else {
4220                 pkiDebug("open_session: prompt for token/smart card failed\n");
4221                 krb5_set_error_message(context, r,
4222                                        gettext("Prompt for token/smart card failed"));
4223                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4224                 goto out;
4225             }
4226         } else {
4227             r = KRB5KDC_ERR_PREAUTH_FAILED;
4228             krb5_set_error_message(context, r,
4229                                    gettext("No smart card tokens found"));
4230             pkiDebug("open_session: no matching token found\n");
4231             goto out;
4232         }
4233     } else if (token_choices.numtokens == 1) {
4234         if ((token_choices.token_array[0].token_info.flags & CKF_LOGIN_REQUIRED) &&
4235             !(cctx->p11flags & C_PROMPTED_USER) &&
4236             do_matching) {
4237             if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4238                 pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4239                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4240                 krb5_set_error_message(context, r,
4241                                        gettext("Prompt for token/smart card failed"));
4242                 goto out;
4243             }
4244             if (choice == RESCAN_TOKENS) {
4245                 /* rescan for new smartcard/token */
4246                 for (i = 0; i < token_choices.numtokens; i++) {
4247                     /* close all sessions */
4248                     cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4249                 }
4250                 free(token_choices.token_array);
4251                 token_choices.token_array = NULL;
4252                 token_choices.numtokens = 0;
4253                 goto tryagain;
4254             } else if (choice == SKIP_TOKENS) {
4255                 /* do not use smartcard/token for auth */
4256                 cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4257                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4258                 goto out;
4259             } else {
4260                 cctx->p11flags |= C_PROMPTED_USER;
4261             }
4262         } else {
4263             choice = 0; /* really the only choice is the first token_array entry */
4264         }
4265     } else if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4266         /* > 1 token so present menu of token choices, let the user decide. */
4267         if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4268             pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4269             r = KRB5KDC_ERR_PREAUTH_FAILED;
4270             krb5_set_error_message(context, r,
4271                                    gettext("Prompt for token/smart card failed"));
4272             goto out;
4273         }
4274         if (choice == RESCAN_TOKENS) {
4275             /* rescan for new smartcard/token */
4276             for (i = 0; i < token_choices.numtokens; i++) {
4277                 /* close all sessions */
4278                 cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4279             }
4280             free(token_choices.token_array);
4281             token_choices.token_array = NULL;
4282             token_choices.numtokens = 0;
4283             goto tryagain;
4284         } else if (choice == SKIP_TOKENS) {
4285             /* do not use smartcard/token for auth */
4286             cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4287             r = KRB5KDC_ERR_PREAUTH_FAILED;
4288             goto out;
4289         } else {
4290             cctx->p11flags |= C_PROMPTED_USER;
4291         }
4292     } else {
4293         r = KRB5KDC_ERR_PREAUTH_FAILED;
4294         goto out;
4295     }
4296 
4297     cctx->slotid = token_choices.token_array[choice].slotID;
4298     cctx->session = token_choices.token_array[choice].session;
4299 
4300     pkiDebug("open_session: slotid %d (%d of %d)\n", (int) cctx->slotid,
4301              i + 1, (int) count);
4302 
4303     /* Login if needed */
4304     /* Solaris Kerberos: added cctx->p11flags check */
4305     if ((token_choices.token_array[choice].token_info.flags & CKF_LOGIN_REQUIRED) &&
4306         !(cctx->p11flags & C_LOGIN_DONE)) {
4307         r = pkinit_login(context, cctx, &token_choices.token_array[choice].token_info);
4308     }
4309 
4310     if (r == 0) {
4311         /* Doing this again to load the certs into cctx. */
4312         r = check_load_certs(context, cctx->session, plg_cryptoctx,
4313                              req_cryptoctx, cctx, princ, do_matching, 1);
4314     }
4315 
4316 out:
4317     if (slotlist != NULL)
4318         free(slotlist);
4319 
4320     if (tmpslotlist != NULL)
4321         free(tmpslotlist);
4322 
4323     if (token_choices.token_array != NULL) {
4324         if (r != 0) {
4325             /* close all sessions if there's an error */
4326             for (i = 0; i < token_choices.numtokens; i++) {
4327                 cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4328             }
4329             cctx->session = CK_INVALID_HANDLE;
4330         } else {
4331             /* close sessions not chosen */
4332             for (i = 0; i < token_choices.numtokens; i++) {
4333                 if (i != choice) {
4334                     cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4335                 }
4336             }
4337         }
4338         free(token_choices.token_array);
4339     }
4340 
4341     return (r);
4342 }
4343 
4344 /*
4345  * Look for a key that's:
4346  * 1. private
4347  * 2. capable of the specified operation (usually signing or decrypting)
4348  * 3. RSA (this may be wrong but it's all we can do for now)
4349  * 4. matches the id of the cert we chose
4350  *
4351  * You must call pkinit_get_certs before calling pkinit_find_private_key
4352  * (that's because we need the ID of the private key)
4353  *
4354  * pkcs11 says the id of the key doesn't have to match that of the cert, but
4355  * I can't figure out any other way to decide which key to use.
4356  *
4357  * We should only find one key that fits all the requirements.
4358  * If there are more than one, we just take the first one.
4359  */
4360 
4361 /* ARGSUSED */
4362 krb5_error_code
4363 pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
4364                         CK_ATTRIBUTE_TYPE usage,
4365                         CK_OBJECT_HANDLE *objp)
4366 {
4367     CK_OBJECT_CLASS cls;
4368     CK_ATTRIBUTE attrs[4];
4369     CK_ULONG count;
4370     CK_KEY_TYPE keytype;
4371     unsigned int nattrs = 0;
4372     int r;
4373 #ifdef PKINIT_USE_KEY_USAGE
4374     CK_BBOOL true_false;
4375 #endif
4376 
4377     cls = CKO_PRIVATE_KEY;
4378     attrs[nattrs].type = CKA_CLASS;
4379     attrs[nattrs].pValue = &cls;
4380     attrs[nattrs].ulValueLen = sizeof cls;
4381     nattrs++;
4382 
4383 #ifdef PKINIT_USE_KEY_USAGE
4384     /*
4385      * Some cards get confused if you try to specify a key usage,
4386      * so don't, and hope for the best. This will fail if you have
4387      * several keys with the same id and different usages but I have
4388      * not seen this on real cards.
4389      */
4390     true_false = TRUE;
4391     attrs[nattrs].type = usage;
4392     attrs[nattrs].pValue = &true_false;
4393     attrs[nattrs].ulValueLen = sizeof true_false;
4394     nattrs++;
4395 #endif
4396 
4397     keytype = CKK_RSA;
4398     attrs[nattrs].type = CKA_KEY_TYPE;
4399     attrs[nattrs].pValue = &keytype;
4400     attrs[nattrs].ulValueLen = sizeof keytype;
4401     nattrs++;
4402 
4403     attrs[nattrs].type = CKA_ID;
4404     attrs[nattrs].pValue = id_cryptoctx->cert_id;
4405     attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
4406     nattrs++;
4407 
4408     r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4409     if (r != CKR_OK) {
4410         pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4411                  pkinit_pkcs11_code_to_text(r));
4412         return KRB5KDC_ERR_PREAUTH_FAILED;
4413     }
4414 
4415     r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4416     id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4417     pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4418 
4419     /*
4420      * Solaris Kerberos:
4421      * The CKA_ID may not be correctly set for the private key. For e.g. when
4422      * storing a private key in softtoken pktool(1) doesn't generate or store
4423      * a CKA_ID for the private key. Another way to identify the private key is
4424      * to look for a private key with the same RSA modulus as the public key
4425      * in the certificate.
4426      */
4427     if (r == CKR_OK && count != 1) {
4428 
4429         EVP_PKEY *priv;
4430         X509 *cert;
4431         unsigned int n_len;
4432         unsigned char *n_bytes;
4433 
4434         cert = sk_X509_value(id_cryptoctx->my_certs, 0);
4435         priv = X509_get_pubkey(cert);
4436         if (priv == NULL) {
4437                 pkiDebug("Failed to extract pub key from cert\n");
4438                 return KRB5KDC_ERR_PREAUTH_FAILED;
4439         }
4440 
4441         nattrs = 0;
4442         cls = CKO_PRIVATE_KEY;
4443         attrs[nattrs].type = CKA_CLASS;
4444         attrs[nattrs].pValue = &cls;
4445         attrs[nattrs].ulValueLen = sizeof cls;
4446         nattrs++;
4447 
4448 #ifdef PKINIT_USE_KEY_USAGE
4449         true_false = TRUE;
4450         attrs[nattrs].type = usage;
4451         attrs[nattrs].pValue = &true_false;
4452         attrs[nattrs].ulValueLen = sizeof true_false;
4453         nattrs++;
4454 #endif
4455 
4456         keytype = CKK_RSA;
4457         attrs[nattrs].type = CKA_KEY_TYPE;
4458         attrs[nattrs].pValue = &keytype;
4459         attrs[nattrs].ulValueLen = sizeof keytype;
4460         nattrs++;
4461 
4462         n_len = BN_num_bytes(priv->pkey.rsa->n);
4463         n_bytes = (unsigned char *) malloc((size_t) n_len);
4464         if (n_bytes == NULL) {
4465                 return (ENOMEM);
4466         }
4467 
4468         if (BN_bn2bin(priv->pkey.rsa->n, n_bytes) == 0) {
4469                 free (n_bytes);
4470                 pkiDebug("zero-byte key modulus\n");
4471                 return KRB5KDC_ERR_PREAUTH_FAILED;
4472         }
4473 
4474         attrs[nattrs].type = CKA_MODULUS;
4475         attrs[nattrs].ulValueLen = n_len; 
4476         attrs[nattrs].pValue = n_bytes;
4477 
4478         nattrs++;
4479 
4480         r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4481         free (n_bytes);
4482         if (r != CKR_OK) {
4483                 pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4484                         pkinit_pkcs11_code_to_text(r));
4485                 return KRB5KDC_ERR_PREAUTH_FAILED;
4486         }
4487 
4488         r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4489         id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4490         pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4491 
4492     }
4493 
4494     if (r != CKR_OK || count < 1)
4495         return KRB5KDC_ERR_PREAUTH_FAILED;
4496     return 0;
4497 }
4498 #endif
4499 
4500 /* ARGSUSED */
4501 static krb5_error_code
4502 pkinit_decode_data_fs(krb5_context context,
4503                       pkinit_identity_crypto_context id_cryptoctx,
4504                       unsigned char *data,
4505                       unsigned int data_len,
4506                       unsigned char **decoded_data,
4507                       unsigned int *decoded_data_len)
4508 {
4509     if (decode_data(decoded_data, decoded_data_len, data, data_len,
4510                 id_cryptoctx->my_key, sk_X509_value(id_cryptoctx->my_certs,
4511                 id_cryptoctx->cert_index)) <= 0) {
4512         pkiDebug("failed to decode data\n");
4513         return KRB5KDC_ERR_PREAUTH_FAILED;
4514     }
4515     return 0;
4516 }
4517 
4518 #ifndef WITHOUT_PKCS11
4519 #ifdef SILLYDECRYPT
4520 CK_RV
4521 pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
4522                  CK_BYTE_PTR pEncryptedData,
4523                  CK_ULONG  ulEncryptedDataLen,
4524                  CK_BYTE_PTR pData,
4525                  CK_ULONG_PTR pulDataLen)
4526 {
4527     CK_RV rv = CKR_OK;
4528 
4529     rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
4530         ulEncryptedDataLen, pData, pulDataLen);
4531     if (rv == CKR_OK) {
4532         pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
4533     }
4534     return rv;
4535 }
4536 #endif
4537 
4538 static krb5_error_code
4539 pkinit_decode_data_pkcs11(krb5_context context,
4540                           pkinit_identity_crypto_context id_cryptoctx,
4541                           unsigned char *data,
4542                           unsigned int data_len,
4543                           unsigned char **decoded_data,
4544                           unsigned int *decoded_data_len)
4545 {
4546     CK_OBJECT_HANDLE obj;
4547     CK_ULONG len;
4548     CK_MECHANISM mech;
4549     unsigned char *cp;
4550     int r;
4551 
4552     /*
4553      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4554      * loaded.
4555      */
4556     assert(id_cryptoctx->p11 != NULL);
4557 
4558     /* Solaris Kerberos: Login, if needed, to access private object */
4559     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
4560         CK_TOKEN_INFO tinfo;
4561 
4562         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
4563         if (r != 0)
4564             return r;
4565 
4566         r = pkinit_login(context, id_cryptoctx, &tinfo);
4567         if (r != 0)
4568             return r;
4569     }
4570 
4571     r = pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj);
4572     if (r != 0)
4573         return r;
4574 
4575     mech.mechanism = CKM_RSA_PKCS;
4576     mech.pParameter = NULL;
4577     mech.ulParameterLen = 0;
4578 
4579     if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech,
4580             obj)) != CKR_OK) {
4581         pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
4582         return KRB5KDC_ERR_PREAUTH_FAILED;
4583     }
4584     pkiDebug("data_len = %d\n", data_len);
4585     cp = (unsigned char *)malloc((size_t) data_len);
4586     if (cp == NULL)
4587         return ENOMEM;
4588     len = data_len;
4589 #ifdef SILLYDECRYPT
4590     pkiDebug("session %x edata %x edata_len %d data %x datalen @%x %d\n",
4591             (int) id_cryptoctx->session, (int) data, (int) data_len, (int) cp,
4592             (int) &len, (int) len);
4593     if ((r = pkinit_C_Decrypt(id_cryptoctx, data, (CK_ULONG) data_len,
4594             cp, &len)) != CKR_OK) {
4595 #else
4596     if ((r = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, data,
4597             (CK_ULONG) data_len, cp, &len)) != CKR_OK) {
4598 #endif
4599         pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
4600         if (r == CKR_BUFFER_TOO_SMALL)
4601             pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
4602         return KRB5KDC_ERR_PREAUTH_FAILED;
4603     }
4604     pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
4605     *decoded_data_len = len;
4606     *decoded_data = cp;
4607 
4608     return 0;
4609 }
4610 #endif
4611 
4612 krb5_error_code
4613 pkinit_decode_data(krb5_context context,
4614                    pkinit_identity_crypto_context id_cryptoctx,
4615                    unsigned char *data,
4616                    unsigned int data_len,
4617                    unsigned char **decoded_data,
4618                    unsigned int *decoded_data_len)
4619 {
4620     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4621 
4622     if (id_cryptoctx->pkcs11_method != 1)
4623         retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len,
4624             decoded_data, decoded_data_len);
4625 #ifndef WITHOUT_PKCS11
4626     else
4627         retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data,
4628             data_len, decoded_data, decoded_data_len);
4629 #endif
4630 
4631     return retval;
4632 }
4633 
4634 /* ARGSUSED */
4635 static krb5_error_code
4636 pkinit_sign_data_fs(krb5_context context,
4637                  pkinit_identity_crypto_context id_cryptoctx,
4638                  unsigned char *data,
4639                  unsigned int data_len,
4640                  unsigned char **sig,
4641                  unsigned int *sig_len)
4642 {
4643     if (create_signature(sig, sig_len, data, data_len,
4644             id_cryptoctx->my_key) != 0) {
4645             pkiDebug("failed to create the signature\n");
4646             return KRB5KDC_ERR_PREAUTH_FAILED;
4647     }
4648     return 0;
4649 }
4650 
4651 #ifndef WITHOUT_PKCS11
4652 static krb5_error_code
4653 pkinit_sign_data_pkcs11(krb5_context context,
4654                         pkinit_identity_crypto_context id_cryptoctx,
4655                         unsigned char *data,
4656                         unsigned int data_len,
4657                         unsigned char **sig,
4658                         unsigned int *sig_len)
4659 {
4660     CK_OBJECT_HANDLE obj;
4661     CK_ULONG len;
4662     CK_MECHANISM mech;
4663     unsigned char *cp;
4664     int r;
4665 
4666     /*
4667      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4668      * loaded.
4669      */
4670     assert(id_cryptoctx->p11 != NULL);
4671 
4672     /* Solaris Kerberos: Login, if needed, to access private object */
4673     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
4674         CK_TOKEN_INFO tinfo;
4675 
4676         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
4677         if (r != 0)
4678             return r;
4679 
4680         r = pkinit_login(context, id_cryptoctx, &tinfo);
4681         if (r != 0)
4682             return r;
4683     }
4684 
4685     r = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
4686     if (r != 0 )
4687         return r;
4688 
4689     mech.mechanism = id_cryptoctx->mech;
4690     mech.pParameter = NULL;
4691     mech.ulParameterLen = 0;
4692 
4693     if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
4694             obj)) != CKR_OK) {
4695         pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r));
4696         return KRB5KDC_ERR_PREAUTH_FAILED;
4697     }
4698 
4699     /*
4700      * Key len would give an upper bound on sig size, but there's no way to
4701      * get that. So guess, and if it's too small, re-malloc.
4702      */
4703     len = PK_SIGLEN_GUESS;
4704     cp = (unsigned char *)malloc((size_t) len);
4705     if (cp == NULL)
4706         return ENOMEM;
4707 
4708     r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4709                                  (CK_ULONG) data_len, cp, &len);
4710     if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
4711         free(cp);
4712         pkiDebug("C_Sign realloc %d\n", (int) len);
4713         cp = (unsigned char *)malloc((size_t) len);
4714         r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4715                                      (CK_ULONG) data_len, cp, &len);
4716     }
4717     if (r != CKR_OK) {
4718         pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r));
4719         return KRB5KDC_ERR_PREAUTH_FAILED;
4720     }
4721     pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
4722     *sig_len = len;
4723     *sig = cp;
4724 
4725     return 0;
4726 }
4727 #endif
4728 
4729 krb5_error_code
4730 pkinit_sign_data(krb5_context context,
4731                  pkinit_identity_crypto_context id_cryptoctx,
4732                  unsigned char *data,
4733                  unsigned int data_len,
4734                  unsigned char **sig,
4735                  unsigned int *sig_len)
4736 {
4737     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4738 
4739     if (id_cryptoctx == NULL || id_cryptoctx->pkcs11_method != 1)
4740         retval = pkinit_sign_data_fs(context, id_cryptoctx, data, data_len,
4741                                      sig, sig_len);
4742 #ifndef WITHOUT_PKCS11
4743     else
4744         retval = pkinit_sign_data_pkcs11(context, id_cryptoctx, data, data_len,
4745                                          sig, sig_len);
4746 #endif
4747 
4748     return retval;
4749 }
4750 
4751 
4752 static krb5_error_code
4753 decode_data(unsigned char **out_data, unsigned int *out_data_len,
4754             unsigned char *data, unsigned int data_len,
4755             EVP_PKEY *pkey, X509 *cert)
4756 {
4757     /* Solaris Kerberos */
4758     int len;
4759     unsigned char *buf = NULL;
4760     int buf_len = 0;
4761 
4762     /* Solaris Kerberos */
4763     if (out_data == NULL || out_data_len == NULL)
4764         return EINVAL;
4765 
4766     if (cert && !X509_check_private_key(cert, pkey)) {
4767         pkiDebug("private key does not match certificate\n");
4768         /* Solaris Kerberos */
4769         return EINVAL;
4770     }
4771 
4772     buf_len = EVP_PKEY_size(pkey);
4773     buf = (unsigned char *)malloc((size_t) buf_len + 10);
4774     if (buf == NULL)
4775         return ENOMEM;
4776 
4777 #if OPENSSL_VERSION_NUMBER < 0x10000000L
4778     len = EVP_PKEY_decrypt(buf, data, (int)data_len, pkey);
4779 #else
4780     len = EVP_PKEY_decrypt_old(buf, data, (int)data_len, pkey);
4781 #endif
4782     if (len <= 0) {
4783         pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
4784         /* Solaris Kerberos */
4785         free(buf);
4786         return KRB5KRB_ERR_GENERIC;
4787     }
4788     *out_data = buf;
4789     *out_data_len = len;
4790 
4791     return 0;
4792 }
4793 
4794 static krb5_error_code
4795 create_signature(unsigned char **sig, unsigned int *sig_len,
4796                  unsigned char *data, unsigned int data_len, EVP_PKEY *pkey)
4797 {
4798     krb5_error_code retval = ENOMEM;
4799     EVP_MD_CTX md_ctx;
4800 
4801     if (pkey == NULL)
4802         /* Solaris Kerberos */
4803         return EINVAL;
4804 
4805     EVP_VerifyInit(&md_ctx, EVP_sha1());
4806     EVP_SignUpdate(&md_ctx, data, data_len);
4807     *sig_len = EVP_PKEY_size(pkey);
4808     if ((*sig = (unsigned char *) malloc((size_t) *sig_len)) == NULL)
4809         goto cleanup;
4810     EVP_SignFinal(&md_ctx, *sig, sig_len, pkey);
4811 
4812     retval = 0;
4813 
4814   cleanup:
4815     EVP_MD_CTX_cleanup(&md_ctx);
4816 
4817     return retval;
4818 }
4819 
4820 /*
4821  * Note:
4822  * This is not the routine the KDC uses to get its certificate.
4823  * This routine is intended to be called by the client
4824  * to obtain the KDC's certificate from some local storage
4825  * to be sent as a hint in its request to the KDC.
4826  */
4827 /* ARGSUSED */
4828 krb5_error_code
4829 pkinit_get_kdc_cert(krb5_context context,
4830                     pkinit_plg_crypto_context plg_cryptoctx,
4831                     pkinit_req_crypto_context req_cryptoctx,
4832                     pkinit_identity_crypto_context id_cryptoctx,
4833                     krb5_principal princ)
4834 {
4835    /* Solaris Kerberos */
4836     if (req_cryptoctx == NULL)
4837         return EINVAL;
4838 
4839     req_cryptoctx->received_cert = NULL;
4840     return 0;
4841 }
4842 
4843 /* ARGSUSED */
4844 static krb5_error_code
4845 pkinit_get_certs_pkcs12(krb5_context context,
4846                           pkinit_plg_crypto_context plg_cryptoctx,
4847                           pkinit_req_crypto_context req_cryptoctx,
4848                           pkinit_identity_opts *idopts,
4849                           pkinit_identity_crypto_context id_cryptoctx,
4850                           krb5_principal princ)
4851 {
4852     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4853     X509 *x = NULL;
4854     PKCS12 *p12 = NULL;
4855     int ret;
4856     FILE *fp;
4857     EVP_PKEY *y = NULL;
4858 
4859     if (idopts->cert_filename == NULL) {
4860         /* Solaris Kerberos: Improved error messages */
4861         krb5_set_error_message(context, retval,
4862             gettext("Failed to get certificate location"));
4863         pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
4864         goto cleanup;
4865     }
4866 
4867     if (idopts->key_filename == NULL) {
4868         /* Solaris Kerberos: Improved error messages */
4869         krb5_set_error_message(context, retval,
4870             gettext("Failed to get private key location"));
4871         pkiDebug("%s: failed to get user's private key location\n", __FUNCTION__);
4872         goto cleanup;
4873     }
4874 
4875     fp = fopen(idopts->cert_filename, "rb");
4876     if (fp == NULL) {
4877         /* Solaris Kerberos: Improved error messages */
4878         krb5_set_error_message(context, retval,
4879             gettext("Failed to open PKCS12 file '%s': %s"),
4880             idopts->cert_filename, error_message(errno));
4881         pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
4882                  idopts->cert_filename, errno);
4883         goto cleanup;
4884     }
4885 
4886     p12 = d2i_PKCS12_fp(fp, NULL);
4887     (void) fclose(fp);
4888     if (p12 == NULL) {
4889         krb5_set_error_message(context, retval,
4890             gettext("Failed to decode PKCS12 file '%s' contents"),
4891             idopts->cert_filename);
4892         pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
4893                  idopts->cert_filename);
4894         goto cleanup;
4895     }
4896     /*
4897      * Try parsing with no pass phrase first.  If that fails,
4898      * prompt for the pass phrase and try again.
4899      */
4900     ret = PKCS12_parse(p12, NULL, &y, &x, NULL);
4901     if (ret == 0) {
4902         krb5_data rdat;
4903         krb5_prompt kprompt;
4904         krb5_prompt_type prompt_type;
4905         int r = 0;
4906         char prompt_string[128];
4907         char prompt_reply[128];
4908         /* Solaris Kerberos */
4909         char *prompt_prefix = gettext("Pass phrase for");
4910 
4911         pkiDebug("Initial PKCS12_parse with no password failed\n");
4912 
4913         if (id_cryptoctx->PIN != NULL) {
4914                 /* Solaris Kerberos: use PIN if set */
4915                 rdat.data = id_cryptoctx->PIN;
4916                 /* note rdat.length isn't needed in this case */
4917         } else {
4918                 (void) memset(prompt_reply, '\0', sizeof(prompt_reply));
4919                 rdat.data = prompt_reply;
4920                 rdat.length = sizeof(prompt_reply);
4921 
4922                 r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
4923                              prompt_prefix, idopts->cert_filename);
4924                 if (r >= sizeof(prompt_string)) {
4925                     pkiDebug("Prompt string, '%s %s', is too long!\n",
4926                              prompt_prefix, idopts->cert_filename);
4927                     goto cleanup;
4928                 }
4929                 kprompt.prompt = prompt_string;
4930                 kprompt.hidden = 1;
4931                 kprompt.reply = &rdat;
4932                 prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
4933 
4934                 /* PROMPTER_INVOCATION */
4935                 k5int_set_prompt_types(context, &prompt_type);
4936                 r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
4937                                               NULL, NULL, 1, &kprompt);
4938                 k5int_set_prompt_types(context, NULL);
4939         }
4940 
4941         ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
4942         if (ret == 0) {
4943             /* Solaris Kerberos: Improved error messages */
4944             krb5_set_error_message(context, retval,
4945                 gettext("Failed to parse PKCS12 file '%s' with password"),
4946                 idopts->cert_filename);
4947             pkiDebug("Seconde PKCS12_parse with password failed\n");
4948             goto cleanup;
4949         }
4950     }
4951     id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
4952     if (id_cryptoctx->creds[0] == NULL)
4953         goto cleanup;
4954     id_cryptoctx->creds[0]->cert = x;
4955 #ifndef WITHOUT_PKCS11
4956     id_cryptoctx->creds[0]->cert_id = NULL;
4957     id_cryptoctx->creds[0]->cert_id_len = 0;
4958 #endif
4959     id_cryptoctx->creds[0]->key = y;
4960     id_cryptoctx->creds[1] = NULL;
4961 
4962     retval = 0;
4963 
4964 cleanup:
4965     if (p12)
4966         PKCS12_free(p12);
4967     if (retval) {
4968         if (x != NULL)
4969             X509_free(x);
4970         if (y != NULL)
4971             EVP_PKEY_free(y);
4972     }
4973     return retval;
4974 }
4975 
4976 static krb5_error_code
4977 pkinit_load_fs_cert_and_key(krb5_context context,
4978                             pkinit_identity_crypto_context id_cryptoctx,
4979                             char *certname,
4980                             char *keyname,
4981                             int cindex)
4982 {
4983     krb5_error_code retval;
4984     X509 *x = NULL;
4985     EVP_PKEY *y = NULL;
4986 
4987     /* load the certificate */
4988     retval = get_cert(certname, &x);
4989     if (retval != 0 || x == NULL) {
4990         /* Solaris Kerberos: Improved error messages */
4991         krb5_set_error_message(context, retval,
4992             gettext("Failed to load user's certificate from %s: %s"),
4993                 certname, error_message(retval));
4994         pkiDebug("failed to load user's certificate from '%s'\n", certname);
4995         goto cleanup;
4996     }
4997     retval = get_key(keyname, &y);
4998     if (retval != 0 || y == NULL) {
4999         /* Solaris Kerberos: Improved error messages */
5000         krb5_set_error_message(context, retval,
5001             gettext("Failed to load user's private key from %s: %s"),
5002                 keyname, error_message(retval));
5003         pkiDebug("failed to load user's private key from '%s'\n", keyname);
5004         goto cleanup;
5005     }
5006 
5007     id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
5008     if (id_cryptoctx->creds[cindex] == NULL) {
5009         retval = ENOMEM;
5010         goto cleanup;
5011     }
5012     id_cryptoctx->creds[cindex]->cert = x;
5013 #ifndef WITHOUT_PKCS11
5014     id_cryptoctx->creds[cindex]->cert_id = NULL;
5015     id_cryptoctx->creds[cindex]->cert_id_len = 0;
5016 #endif
5017     id_cryptoctx->creds[cindex]->key = y;
5018     id_cryptoctx->creds[cindex+1] = NULL;
5019 
5020     retval = 0;
5021 
5022 cleanup:
5023     if (retval) {
5024         if (x != NULL)
5025             X509_free(x);
5026         if (y != NULL)
5027             EVP_PKEY_free(y);
5028     }
5029     return retval;
5030 }
5031 
5032 /* ARGSUSED */
5033 static krb5_error_code
5034 pkinit_get_certs_fs(krb5_context context,
5035                           pkinit_plg_crypto_context plg_cryptoctx,
5036                           pkinit_req_crypto_context req_cryptoctx,
5037                           pkinit_identity_opts *idopts,
5038                           pkinit_identity_crypto_context id_cryptoctx,
5039                           krb5_principal princ)
5040 {
5041     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
5042 
5043     if (idopts->cert_filename == NULL) {
5044         pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
5045         goto cleanup;
5046     }
5047 
5048     if (idopts->key_filename == NULL) {
5049         pkiDebug("%s: failed to get user's private key location\n",
5050                  __FUNCTION__);
5051         goto cleanup;
5052     }
5053 
5054     retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5055                                          idopts->cert_filename,
5056                                          idopts->key_filename, 0);
5057 cleanup:
5058     return retval;
5059 }
5060 
5061 /* ARGSUSED */
5062 static krb5_error_code
5063 pkinit_get_certs_dir(krb5_context context,
5064                      pkinit_plg_crypto_context plg_cryptoctx,
5065                      pkinit_req_crypto_context req_cryptoctx,
5066                      pkinit_identity_opts *idopts,
5067                      pkinit_identity_crypto_context id_cryptoctx,
5068                      krb5_principal princ)
5069 {
5070     /* Solaris Kerberos */
5071     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
5072     DIR *d = NULL;
5073     struct dirent *dentry = NULL;
5074     char certname[1024];
5075     char keyname[1024];
5076     int i = 0, len;
5077     char *dirname, *suf;
5078 
5079     /* Solaris Kerberos */
5080     if (idopts == NULL)
5081         return EINVAL;
5082 
5083     if (idopts->cert_filename == NULL) {
5084         pkiDebug("%s: failed to get user's certificate directory location\n",
5085                  __FUNCTION__);
5086         return ENOENT;
5087     }
5088 
5089     dirname = idopts->cert_filename;
5090     d = opendir(dirname);
5091     if (d == NULL) {
5092         /* Solaris Kerberos: Improved error messages */
5093         krb5_set_error_message(context, errno,
5094             gettext("Failed to open directory \"%s\": %s"),
5095             dirname, error_message(errno));
5096         return errno;
5097     }
5098 
5099     /*
5100      * We'll assume that certs are named XXX.crt and the corresponding
5101      * key is named XXX.key
5102      */
5103     while ((i < MAX_CREDS_ALLOWED) &&  (dentry = readdir(d)) != NULL) {
5104         /* Ignore subdirectories and anything starting with a dot */
5105 #ifdef DT_DIR
5106         if (dentry->d_type == DT_DIR)
5107             continue;
5108 #endif
5109         if (dentry->d_name[0] == '.')
5110             continue;
5111         len = strlen(dentry->d_name);
5112         if (len < 5)
5113             continue;
5114         suf = dentry->d_name + (len - 4);
5115         if (strncmp(suf, ".crt", 4) != 0)
5116             continue;
5117 
5118         /* Checked length */
5119         if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(certname)) {
5120             pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5121                      __FUNCTION__, dirname, dentry->d_name);
5122             continue;
5123         }
5124         (void) snprintf(certname, sizeof(certname), "%s/%s", dirname, dentry->d_name);
5125         (void) snprintf(keyname, sizeof(keyname), "%s/%s", dirname, dentry->d_name);
5126         len = strlen(keyname);
5127         keyname[len - 3] = 'k';
5128         keyname[len - 2] = 'e';
5129         keyname[len - 1] = 'y';
5130 
5131         retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5132                                              certname, keyname, i);
5133         if (retval == 0) {
5134             pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
5135                      __FUNCTION__, dentry->d_name);
5136             i++;
5137         }
5138         else
5139             continue;
5140     }
5141 
5142     if (i == 0) {
5143         /* Solaris Kerberos: Improved error messages */
5144         krb5_set_error_message(context, ENOENT,
5145             gettext("No suitable cert/key pairs found in directory '%s'"),
5146             idopts->cert_filename);
5147         pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
5148                  __FUNCTION__, idopts->cert_filename);
5149         retval = ENOENT;
5150         goto cleanup;
5151     }
5152 
5153     retval = 0;
5154 
5155   cleanup:
5156     if (d) 
5157         (void) closedir(d);
5158 
5159     return retval;
5160 }
5161 
5162 #ifndef WITHOUT_PKCS11
5163 /* ARGSUSED */
5164 static krb5_error_code
5165 pkinit_get_certs_pkcs11(krb5_context context,
5166                         pkinit_plg_crypto_context plg_cryptoctx,
5167                         pkinit_req_crypto_context req_cryptoctx,
5168                         pkinit_identity_opts *idopts,
5169                         pkinit_identity_crypto_context id_cryptoctx,
5170                         krb5_principal princ,
5171                         int do_matching)
5172 {
5173 #ifdef PKINIT_USE_MECH_LIST
5174     CK_MECHANISM_TYPE_PTR mechp = NULL;
5175     CK_MECHANISM_INFO info;
5176 #endif
5177 
5178     if (id_cryptoctx->p11flags & C_SKIP_PKCS11_AUTH)
5179         return KRB5KDC_ERR_PREAUTH_FAILED;
5180 
5181     /* Copy stuff from idopts -> id_cryptoctx */
5182     if (idopts->p11_module_name != NULL) {
5183         id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
5184         if (id_cryptoctx->p11_module_name == NULL)
5185             return ENOMEM;
5186     }
5187     if (idopts->token_label != NULL) {
5188         id_cryptoctx->token_label = strdup(idopts->token_label);
5189         if (id_cryptoctx->token_label == NULL)
5190             return ENOMEM;
5191     }
5192     if (idopts->cert_label != NULL) {
5193         id_cryptoctx->cert_label = strdup(idopts->cert_label);
5194         if (id_cryptoctx->cert_label == NULL)
5195             return ENOMEM;
5196     }
5197     if (idopts->PIN != NULL) {
5198         id_cryptoctx->PIN = strdup(idopts->PIN);
5199         if (id_cryptoctx->PIN == NULL)
5200             return ENOMEM;
5201     }
5202     /* Convert the ascii cert_id string into a binary blob */
5203     /*
5204      * Solaris Kerberos:
5205      * If the cert_id_string is empty then behave in a similar way to how
5206      * an empty certlabel is treated - i.e. don't fail now but rather continue
5207      * as though the certid wasn't specified.
5208      */
5209     if (idopts->cert_id_string != NULL && strlen(idopts->cert_id_string) != 0) {
5210         BIGNUM *bn = NULL;
5211         BN_hex2bn(&bn, idopts->cert_id_string);
5212         if (bn == NULL)
5213             return ENOMEM;
5214         id_cryptoctx->cert_id_len = BN_num_bytes(bn);
5215         id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
5216         if (id_cryptoctx->cert_id == NULL) {
5217             BN_free(bn);
5218             return ENOMEM;
5219         }
5220         BN_bn2bin(bn, id_cryptoctx->cert_id);
5221         BN_free(bn);
5222     }
5223     id_cryptoctx->slotid = idopts->slotid;
5224     id_cryptoctx->pkcs11_method = 1;
5225 
5226 #ifndef PKINIT_USE_MECH_LIST
5227     /*
5228      * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
5229      * many cards seems to be confused about whether they are capable of
5230      * this or not. The safe thing seems to be to ignore the mechanism list,
5231      * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
5232      */
5233 
5234     id_cryptoctx->mech = CKM_RSA_PKCS;
5235 #else
5236     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL,
5237             &count)) != CKR_OK || count <= 0) {
5238         pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r));
5239         return KRB5KDC_ERR_PREAUTH_FAILED;
5240     }
5241     mechp = (CK_MECHANISM_TYPE_PTR) malloc(count * sizeof (CK_MECHANISM_TYPE));
5242     if (mechp == NULL)
5243         return ENOMEM;
5244     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid,
5245             mechp, &count)) != CKR_OK) {
5246         free(mechp);
5247         return KRB5KDC_ERR_PREAUTH_FAILED;
5248     }
5249     for (i = 0; i < count; i++) {
5250         if ((r = id_cryptoctx->p11->C_GetMechanismInfo(id_cryptoctx->slotid,
5251                 mechp[i], &info)) != CKR_OK) {
5252             free(mechp);
5253             return KRB5KDC_ERR_PREAUTH_FAILED;
5254         }
5255 #ifdef DEBUG_MECHINFO
5256         pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
5257         if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
5258             pkiDebug("  this mech is good for sign & decrypt\n");
5259 #endif
5260         if (mechp[i] == CKM_RSA_PKCS) {
5261             /* This seems backwards... */
5262             id_cryptoctx->mech =
5263                 (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
5264         }
5265     }
5266     free(mechp);
5267 
5268     pkiDebug("got %d mechs from card\n", (int) count);
5269 #endif
5270 
5271     return (pkinit_open_session(context, plg_cryptoctx, req_cryptoctx,
5272                                 id_cryptoctx, princ, do_matching));
5273 }
5274 #endif
5275 
5276 /* ARGSUSED */
5277 static void
5278 free_cred_info(krb5_context context,
5279                pkinit_identity_crypto_context id_cryptoctx,
5280                struct _pkinit_cred_info *cred)
5281 {
5282     if (cred != NULL) {
5283         if (cred->cert != NULL)
5284             X509_free(cred->cert);
5285         if (cred->key != NULL)
5286             EVP_PKEY_free(cred->key);
5287 #ifndef WITHOUT_PKCS11
5288         if (cred->cert_id != NULL)
5289             free(cred->cert_id);
5290 #endif
5291         free(cred);
5292     }
5293 }
5294 
5295 /* ARGSUSED */
5296 krb5_error_code
5297 crypto_free_cert_info(krb5_context context,
5298                       pkinit_plg_crypto_context plg_cryptoctx,
5299                       pkinit_req_crypto_context req_cryptoctx,
5300                       pkinit_identity_crypto_context id_cryptoctx)
5301 {
5302     int i;
5303 
5304     if (id_cryptoctx == NULL)
5305         return EINVAL;
5306 
5307     for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
5308         if (id_cryptoctx->creds[i] != NULL) {
5309             free_cred_info(context, id_cryptoctx, id_cryptoctx->creds[i]);
5310             id_cryptoctx->creds[i] = NULL;
5311         }
5312     }
5313     return 0;
5314 }
5315 
5316 krb5_error_code
5317 crypto_load_certs(krb5_context context,
5318                   pkinit_plg_crypto_context plg_cryptoctx,
5319                   pkinit_req_crypto_context req_cryptoctx,
5320                   pkinit_identity_opts *idopts,
5321                   pkinit_identity_crypto_context id_cryptoctx,
5322                   krb5_principal princ,
5323                   int do_matching)
5324 {
5325     krb5_error_code retval;
5326 
5327     switch(idopts->idtype) {
5328         case IDTYPE_FILE:
5329             retval = pkinit_get_certs_fs(context, plg_cryptoctx,
5330                                          req_cryptoctx, idopts,
5331                                          id_cryptoctx, princ);
5332             break;
5333         case IDTYPE_DIR:
5334             retval = pkinit_get_certs_dir(context, plg_cryptoctx,
5335                                           req_cryptoctx, idopts,
5336                                           id_cryptoctx, princ);
5337             break;
5338 #ifndef WITHOUT_PKCS11
5339         case IDTYPE_PKCS11:
5340             retval = pkinit_get_certs_pkcs11(context, plg_cryptoctx,
5341                                              req_cryptoctx, idopts,
5342                                              id_cryptoctx, princ, do_matching);
5343             break;
5344 #endif
5345         case IDTYPE_PKCS12:
5346             retval = pkinit_get_certs_pkcs12(context, plg_cryptoctx,
5347                                              req_cryptoctx, idopts,
5348                                              id_cryptoctx, princ);
5349                 break;
5350         default:
5351             retval = EINVAL;
5352     }
5353 /* Solaris Kerberos */
5354 
5355     return retval;
5356 }
5357 
5358 /*
5359  * Get number of certificates available after crypto_load_certs()
5360  */
5361 /* ARGSUSED */
5362 krb5_error_code
5363 crypto_cert_get_count(krb5_context context,
5364                       pkinit_plg_crypto_context plg_cryptoctx,
5365                       pkinit_req_crypto_context req_cryptoctx,
5366                       pkinit_identity_crypto_context id_cryptoctx,
5367                       int *cert_count)
5368 {
5369     int count;
5370 
5371     if (id_cryptoctx == NULL || id_cryptoctx->creds[0] == NULL)
5372         return EINVAL;
5373 
5374     for (count = 0;
5375          count <= MAX_CREDS_ALLOWED && id_cryptoctx->creds[count] != NULL;
5376          count++);
5377     *cert_count = count;
5378     return 0;
5379 }
5380 
5381 
5382 /*
5383  * Begin iteration over the certs loaded in crypto_load_certs()
5384  */
5385 /* ARGSUSED */
5386 krb5_error_code
5387 crypto_cert_iteration_begin(krb5_context context,
5388                             pkinit_plg_crypto_context plg_cryptoctx,
5389                             pkinit_req_crypto_context req_cryptoctx,
5390                             pkinit_identity_crypto_context id_cryptoctx,
5391                             pkinit_cert_iter_handle *ih_ret)
5392 {
5393     struct _pkinit_cert_iter_data *id;
5394 
5395     if (id_cryptoctx == NULL || ih_ret == NULL)
5396         return EINVAL;
5397     if (id_cryptoctx->creds[0] == NULL)      /* No cred info available */
5398         return ENOENT;
5399 
5400     id = calloc(1, sizeof(*id));
5401     if (id == NULL)
5402         return ENOMEM;
5403     id->magic = ITER_MAGIC;
5404     id->plgctx = plg_cryptoctx,
5405     id->reqctx = req_cryptoctx,
5406     id->idctx = id_cryptoctx;
5407     id->index = 0;
5408     *ih_ret = (pkinit_cert_iter_handle) id;
5409     return 0;
5410 }
5411 
5412 /*
5413  * End iteration over the certs loaded in crypto_load_certs()
5414  */
5415 /* ARGSUSED */
5416 krb5_error_code
5417 crypto_cert_iteration_end(krb5_context context,
5418                           pkinit_cert_iter_handle ih)
5419 {
5420     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5421 
5422     if (id == NULL || id->magic != ITER_MAGIC)
5423         return EINVAL;
5424     free(ih);
5425     return 0;
5426 }
5427 
5428 /*
5429  * Get next certificate handle
5430  */
5431 /* ARGSUSED */
5432 krb5_error_code
5433 crypto_cert_iteration_next(krb5_context context,
5434                            pkinit_cert_iter_handle ih,
5435                            pkinit_cert_handle *ch_ret)
5436 {
5437     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5438     struct _pkinit_cert_data *cd;
5439     pkinit_identity_crypto_context id_cryptoctx;
5440 
5441     if (id == NULL || id->magic != ITER_MAGIC)
5442         return EINVAL;
5443 
5444     if (ch_ret == NULL)
5445         return EINVAL;
5446 
5447     id_cryptoctx = id->idctx;
5448     if (id_cryptoctx == NULL)
5449         return EINVAL;
5450 
5451     if (id_cryptoctx->creds[id->index] == NULL)
5452         return PKINIT_ITER_NO_MORE;
5453     
5454     cd = calloc(1, sizeof(*cd));
5455     if (cd == NULL)
5456         return ENOMEM;
5457 
5458     cd->magic = CERT_MAGIC;
5459     cd->plgctx = id->plgctx;
5460     cd->reqctx = id->reqctx;
5461     cd->idctx = id->idctx;
5462     cd->index = id->index;
5463     cd->cred = id_cryptoctx->creds[id->index++];
5464     *ch_ret = (pkinit_cert_handle)cd;
5465     return 0;
5466 }
5467 
5468 /*
5469  * Release cert handle
5470  */
5471 /* ARGSUSED */
5472 krb5_error_code
5473 crypto_cert_release(krb5_context context,
5474                     pkinit_cert_handle ch)
5475 {
5476     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5477     if (cd == NULL || cd->magic != CERT_MAGIC)
5478         return EINVAL;
5479     free(cd);
5480     return 0;
5481 }
5482 
5483 /*
5484  * Get certificate Key Usage and Extended Key Usage
5485  */
5486 /* ARGSUSED */
5487 static krb5_error_code
5488 crypto_retieve_X509_key_usage(krb5_context context,
5489                               pkinit_plg_crypto_context plgcctx,
5490                               pkinit_req_crypto_context reqcctx,
5491                               X509 *x,
5492                               unsigned int *ret_ku_bits,
5493                               unsigned int *ret_eku_bits)
5494 {
5495     /* Solaris Kerberos */
5496     int i;
5497     unsigned int eku_bits = 0, ku_bits = 0;
5498     ASN1_BIT_STRING *usage = NULL;
5499 
5500     if (ret_ku_bits == NULL && ret_eku_bits == NULL)
5501         return EINVAL;
5502 
5503     if (ret_eku_bits)
5504         *ret_eku_bits = 0;
5505     else {
5506         pkiDebug("%s: EKUs not requested, not checking\n", __FUNCTION__);
5507         goto check_kus;
5508     }
5509     
5510     /* Start with Extended Key usage */
5511     i = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
5512     if (i >= 0) {
5513         EXTENDED_KEY_USAGE *eku;
5514 
5515         eku = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL);
5516         if (eku) {
5517             for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
5518                 ASN1_OBJECT *certoid;
5519                 certoid = sk_ASN1_OBJECT_value(eku, i);
5520                 if ((OBJ_cmp(certoid, plgcctx->id_pkinit_KPClientAuth)) == 0)
5521                     eku_bits |= PKINIT_EKU_PKINIT;
5522                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_ms_smartcard_login))) == 0)
5523                     eku_bits |= PKINIT_EKU_MSSCLOGIN;
5524                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_client_auth))) == 0)
5525                     eku_bits |= PKINIT_EKU_CLIENTAUTH;
5526                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_email_protect))) == 0)
5527                     eku_bits |= PKINIT_EKU_EMAILPROTECTION;
5528             }
5529             EXTENDED_KEY_USAGE_free(eku);
5530         }
5531     }
5532     pkiDebug("%s: returning eku 0x%08x\n", __FUNCTION__, eku_bits);
5533     *ret_eku_bits = eku_bits;
5534 
5535 check_kus:
5536     /* Now the Key Usage bits */
5537     if (ret_ku_bits)
5538         *ret_ku_bits = 0;
5539     else {
5540         pkiDebug("%s: KUs not requested, not checking\n", __FUNCTION__);
5541         goto out;
5542     }
5543 
5544     /* Make sure usage exists before checking bits */
5545     usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL);
5546     if (usage) {
5547         if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
5548             ku_bits |= PKINIT_KU_DIGITALSIGNATURE;
5549         if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
5550             ku_bits |= PKINIT_KU_KEYENCIPHERMENT;
5551         ASN1_BIT_STRING_free(usage);
5552     }
5553 
5554     pkiDebug("%s: returning ku 0x%08x\n", __FUNCTION__, ku_bits);
5555     *ret_ku_bits = ku_bits;
5556 
5557 out:
5558     return 0;
5559 }
5560 
5561 /*
5562  * Return a string format of an X509_NAME in buf where
5563  * size is an in/out parameter.  On input it is the size
5564  * of the buffer, and on output it is the actual length
5565  * of the name.
5566  * If buf is NULL, returns the length req'd to hold name
5567  */
5568 static char *
5569 X509_NAME_oneline_ex(X509_NAME * a,
5570                      char *buf,
5571                      unsigned int *size,
5572                      unsigned long flag)
5573 {
5574   BIO *out = NULL;
5575 
5576   out = BIO_new(BIO_s_mem ());
5577   if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
5578     if (buf != NULL && *size > (int) BIO_number_written(out)) {
5579       (void) memset(buf, 0, *size);
5580       BIO_read(out, buf, (int) BIO_number_written(out));
5581     }
5582     else {
5583       *size = BIO_number_written(out);
5584     }
5585   }
5586   BIO_free(out);
5587   return (buf);
5588 }
5589 
5590 /*
5591  * Get certificate information
5592  */
5593 krb5_error_code
5594 crypto_cert_get_matching_data(krb5_context context,
5595                               pkinit_cert_handle ch,
5596                               pkinit_cert_matching_data **ret_md)
5597 {
5598     krb5_error_code retval;
5599     pkinit_cert_matching_data *md;
5600     krb5_principal *pkinit_sans =NULL, *upn_sans = NULL;
5601     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5602     int i, j;
5603     char buf[DN_BUF_LEN];
5604     unsigned int bufsize = sizeof(buf);
5605 
5606     if (cd == NULL || cd->magic != CERT_MAGIC)
5607         return EINVAL;
5608     if (ret_md == NULL)
5609         return EINVAL;
5610 
5611     md = calloc(1, sizeof(*md));
5612     if (md == NULL)
5613         return ENOMEM;
5614 
5615     md->ch = ch;
5616 
5617     /* get the subject name (in rfc2253 format) */
5618     X509_NAME_oneline_ex(X509_get_subject_name(cd->cred->cert),
5619                          buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5620     md->subject_dn = strdup(buf);
5621     if (md->subject_dn == NULL) {
5622         retval = ENOMEM;
5623         goto cleanup;
5624     }
5625 
5626     /* get the issuer name (in rfc2253 format) */
5627     X509_NAME_oneline_ex(X509_get_issuer_name(cd->cred->cert),
5628                          buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5629     md->issuer_dn = strdup(buf);
5630     if (md->issuer_dn == NULL) {
5631         retval = ENOMEM;
5632         goto cleanup;
5633     }
5634 
5635     /* get the san data */
5636     retval = crypto_retrieve_X509_sans(context, cd->plgctx, cd->reqctx,
5637                                        cd->cred->cert, &pkinit_sans,
5638                                        &upn_sans, NULL);
5639     if (retval)
5640         goto cleanup;
5641 
5642     j = 0;
5643     if (pkinit_sans != NULL) {
5644         for (i = 0; pkinit_sans[i] != NULL; i++)
5645             j++;
5646     }
5647     if (upn_sans != NULL) {
5648         for (i = 0; upn_sans[i] != NULL; i++)
5649             j++;
5650     }
5651     if (j != 0) {
5652         md->sans = calloc((size_t)j+1, sizeof(*md->sans));
5653         if (md->sans == NULL) {
5654             retval = ENOMEM;
5655             goto cleanup;
5656         }
5657         j = 0;
5658         if (pkinit_sans != NULL) {
5659             for (i = 0; pkinit_sans[i] != NULL; i++)
5660                 md->sans[j++] = pkinit_sans[i];
5661             free(pkinit_sans);
5662         }
5663         if (upn_sans != NULL) {
5664             for (i = 0; upn_sans[i] != NULL; i++)
5665                 md->sans[j++] = upn_sans[i];
5666             free(upn_sans);
5667         }
5668         md->sans[j] = NULL;
5669     } else
5670         md->sans = NULL;
5671 
5672     /* get the KU and EKU data */
5673 
5674     retval = crypto_retieve_X509_key_usage(context, cd->plgctx, cd->reqctx,
5675                                            cd->cred->cert,
5676                                            &md->ku_bits, &md->eku_bits);
5677     if (retval)
5678         goto cleanup;
5679 
5680     *ret_md = md;
5681     retval = 0;
5682 cleanup:
5683     if (retval) {
5684         if (md)
5685             crypto_cert_free_matching_data(context, md);
5686     }
5687     return retval;
5688 }
5689 
5690 /*
5691  * Free certificate information
5692  */
5693 krb5_error_code
5694 crypto_cert_free_matching_data(krb5_context context,
5695                       pkinit_cert_matching_data *md)
5696 {
5697     krb5_principal p;
5698     int i;
5699 
5700     if (md == NULL)
5701         return EINVAL;
5702     if (md->subject_dn)
5703         free(md->subject_dn);
5704     if (md->issuer_dn)
5705         free(md->issuer_dn);
5706     if (md->sans) {
5707         for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i])
5708             krb5_free_principal(context, p);
5709         free(md->sans);
5710     }
5711     free(md);
5712     return 0;
5713 }
5714 
5715 /*
5716  * Make this matching certificate "the chosen one"
5717  */
5718 /* ARGSUSED */
5719 krb5_error_code
5720 crypto_cert_select(krb5_context context,
5721                    pkinit_cert_matching_data *md)
5722 {
5723     struct _pkinit_cert_data *cd;
5724     if (md == NULL)
5725         return EINVAL;
5726 
5727     cd = (struct _pkinit_cert_data *)md->ch;
5728     if (cd == NULL || cd->magic != CERT_MAGIC)
5729         return EINVAL;
5730     
5731     /* copy the selected cert into our id_cryptoctx */ 
5732     if (cd->idctx->my_certs != NULL) {
5733         sk_X509_pop_free(cd->idctx->my_certs, X509_free);
5734     }
5735     cd->idctx->my_certs = sk_X509_new_null();     
5736     sk_X509_push(cd->idctx->my_certs, cd->cred->cert);
5737     cd->idctx->creds[cd->index]->cert = NULL;           /* Don't free it twice */
5738     cd->idctx->cert_index = 0;
5739 
5740     if (cd->idctx->pkcs11_method != 1) {
5741         cd->idctx->my_key = cd->cred->key;
5742         cd->idctx->creds[cd->index]->key = NULL;    /* Don't free it twice */
5743     } 
5744 #ifndef WITHOUT_PKCS11
5745     else {
5746         cd->idctx->cert_id = cd->cred->cert_id;
5747         cd->idctx->creds[cd->index]->cert_id = NULL; /* Don't free it twice */
5748         cd->idctx->cert_id_len = cd->cred->cert_id_len;
5749     }
5750 #endif
5751     return 0;
5752 }
5753 
5754 /*
5755  * Choose the default certificate as "the chosen one"
5756  */
5757 krb5_error_code
5758 crypto_cert_select_default(krb5_context context,
5759                            pkinit_plg_crypto_context plg_cryptoctx,
5760                            pkinit_req_crypto_context req_cryptoctx,
5761                            pkinit_identity_crypto_context id_cryptoctx)
5762 {
5763     krb5_error_code retval;
5764     int cert_count = 0;
5765 
5766     retval = crypto_cert_get_count(context, plg_cryptoctx, req_cryptoctx,
5767                                    id_cryptoctx, &cert_count);
5768     if (retval) {
5769         pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
5770                  __FUNCTION__, retval, error_message(retval));
5771         goto errout;
5772     }
5773     if (cert_count != 1) {
5774         /* Solaris Kerberos: Improved error messages */
5775         retval = EINVAL;
5776         krb5_set_error_message(context, retval,
5777             gettext("Failed to select default certificate: "
5778                 "found %d certs to choose from but there must be exactly one"),
5779             cert_count);
5780         pkiDebug("%s: ERROR: There are %d certs to choose from, "
5781                  "but there must be exactly one.\n",
5782                  __FUNCTION__, cert_count);
5783         goto errout;
5784     }
5785     /* copy the selected cert into our id_cryptoctx */ 
5786     if (id_cryptoctx->my_certs != NULL) {
5787         sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
5788     }
5789     id_cryptoctx->my_certs = sk_X509_new_null();     
5790     sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
5791     id_cryptoctx->creds[0]->cert = NULL;  /* Don't free it twice */
5792     id_cryptoctx->cert_index = 0;
5793 
5794     if (id_cryptoctx->pkcs11_method != 1) {
5795         id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
5796         id_cryptoctx->creds[0]->key = NULL;       /* Don't free it twice */
5797     } 
5798 #ifndef WITHOUT_PKCS11
5799     else {
5800         id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
5801         id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
5802         id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
5803     }
5804 #endif
5805     retval = 0;
5806 errout:
5807     return retval;
5808 }
5809 
5810 
5811 /* ARGSUSED */
5812 static krb5_error_code
5813 load_cas_and_crls(krb5_context context,
5814                   pkinit_plg_crypto_context plg_cryptoctx,
5815                   pkinit_req_crypto_context req_cryptoctx,
5816                   pkinit_identity_crypto_context id_cryptoctx,
5817                   int catype,
5818                   char *filename)
5819 {
5820     STACK_OF(X509_INFO) *sk = NULL;
5821     STACK_OF(X509) *ca_certs = NULL;
5822     STACK_OF(X509_CRL) *ca_crls = NULL;
5823     BIO *in = NULL;
5824     /* Solaris Kerberos */
5825     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
5826     int i = 0;
5827 
5828     /* If there isn't already a stack in the context,
5829      * create a temporary one now */
5830     switch(catype) {
5831     case CATYPE_ANCHORS:
5832         if (id_cryptoctx->trustedCAs != NULL)
5833             ca_certs = id_cryptoctx->trustedCAs;
5834         else {
5835             ca_certs = sk_X509_new_null();
5836             if (ca_certs == NULL)
5837                 return ENOMEM;
5838         }
5839         break;
5840     case CATYPE_INTERMEDIATES:
5841         if (id_cryptoctx->intermediateCAs != NULL)
5842             ca_certs = id_cryptoctx->intermediateCAs;
5843         else {
5844             ca_certs = sk_X509_new_null();
5845             if (ca_certs == NULL)
5846                 return ENOMEM;
5847         }
5848         break;
5849     case CATYPE_CRLS:
5850         if (id_cryptoctx->revoked != NULL)
5851             ca_crls = id_cryptoctx->revoked;
5852         else {
5853             ca_crls = sk_X509_CRL_new_null();
5854             if (ca_crls == NULL)
5855                 return ENOMEM;
5856         }
5857         break;
5858     default:
5859         return ENOTSUP;
5860     }
5861 
5862     if (!(in = BIO_new_file(filename, "r"))) {
5863         retval = errno;
5864         pkiDebug("%s: error opening file '%s': %s\n", __FUNCTION__,
5865                  filename, error_message(errno));
5866         goto cleanup;
5867     }
5868 
5869     /* This loads from a file, a stack of x509/crl/pkey sets */
5870     if ((sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) {
5871         pkiDebug("%s: error reading file '%s'\n", __FUNCTION__, filename);
5872         retval = EIO;
5873         goto cleanup;
5874     }
5875 
5876     /* scan over the stack created from loading the file contents,
5877      * weed out duplicates, and push new ones onto the return stack
5878      */
5879     for (i = 0; i < sk_X509_INFO_num(sk); i++) {
5880         X509_INFO *xi = sk_X509_INFO_value(sk, i);
5881         if (xi != NULL && xi->x509 != NULL && catype != CATYPE_CRLS) { 
5882             int j = 0, size = sk_X509_num(ca_certs), flag = 0;
5883 
5884             if (!size) {
5885                 sk_X509_push(ca_certs, xi->x509);
5886                 xi->x509 = NULL;
5887                 continue;
5888             }
5889             for (j = 0; j < size; j++) {
5890                 X509 *x = sk_X509_value(ca_certs, j);
5891                 flag = X509_cmp(x, xi->x509);
5892                 if (flag == 0)
5893                     break;
5894                 else 
5895                     continue;
5896             }
5897             if (flag != 0) {
5898                 sk_X509_push(ca_certs, X509_dup(xi->x509));
5899             }
5900         } else if (xi != NULL && xi->crl != NULL && catype == CATYPE_CRLS) {
5901             int j = 0, size = sk_X509_CRL_num(ca_crls), flag = 0;
5902             if (!size) {
5903                 sk_X509_CRL_push(ca_crls, xi->crl);
5904                 xi->crl = NULL;
5905                 continue;
5906             }
5907             for (j = 0; j < size; j++) {
5908                 X509_CRL *x = sk_X509_CRL_value(ca_crls, j);
5909                 flag = X509_CRL_cmp(x, xi->crl);
5910                 if (flag == 0)
5911                     break;
5912                 else
5913                     continue;
5914             }
5915             if (flag != 0) {
5916                 sk_X509_CRL_push(ca_crls, X509_CRL_dup(xi->crl));
5917             }
5918         }
5919     }
5920 
5921     /* If we added something and there wasn't a stack in the
5922      * context before, add the temporary stack to the context.
5923      */
5924     switch(catype) {
5925     case CATYPE_ANCHORS:
5926         if (sk_X509_num(ca_certs) == 0) {
5927             pkiDebug("no anchors in file, %s\n", filename);
5928             if (id_cryptoctx->trustedCAs == NULL) 
5929                 sk_X509_free(ca_certs);
5930         } else {
5931             if (id_cryptoctx->trustedCAs == NULL)
5932                 id_cryptoctx->trustedCAs = ca_certs;
5933         }
5934         break;
5935     case CATYPE_INTERMEDIATES:
5936         if (sk_X509_num(ca_certs) == 0) {
5937             pkiDebug("no intermediates in file, %s\n", filename);
5938             if (id_cryptoctx->intermediateCAs == NULL) 
5939                 sk_X509_free(ca_certs);
5940         } else {
5941             if (id_cryptoctx->intermediateCAs == NULL)
5942                 id_cryptoctx->intermediateCAs = ca_certs;
5943         }
5944         break;
5945     case CATYPE_CRLS:
5946         if (sk_X509_CRL_num(ca_crls) == 0) {
5947             pkiDebug("no crls in file, %s\n", filename);
5948             if (id_cryptoctx->revoked == NULL)
5949                 sk_X509_CRL_free(ca_crls);
5950         } else {
5951             if (id_cryptoctx->revoked == NULL)
5952                 id_cryptoctx->revoked = ca_crls;
5953         }
5954         break;
5955     default:
5956         /* Should have been caught above! */
5957         retval = EINVAL;
5958         goto cleanup;
5959         /* Solaris Kerberos: removed "break" as it's never reached */
5960     }
5961 
5962     retval = 0;
5963 
5964   cleanup:
5965     if (in != NULL)
5966         BIO_free(in);
5967     if (sk != NULL)
5968         sk_X509_INFO_pop_free(sk, X509_INFO_free);
5969 
5970     return retval;
5971 }
5972 
5973 static krb5_error_code
5974 load_cas_and_crls_dir(krb5_context context,
5975                       pkinit_plg_crypto_context plg_cryptoctx,
5976                       pkinit_req_crypto_context req_cryptoctx,
5977                       pkinit_identity_crypto_context id_cryptoctx,
5978                       int catype,
5979                       char *dirname) 
5980 {
5981     krb5_error_code retval = EINVAL;
5982     DIR *d = NULL;
5983     struct dirent *dentry = NULL;
5984     char filename[1024];
5985 
5986     if (dirname == NULL)
5987         return EINVAL;
5988 
5989     d = opendir(dirname);
5990     if (d == NULL) 
5991         return ENOENT;
5992 
5993     while ((dentry = readdir(d))) {
5994         if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(filename)) {
5995             pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5996                      __FUNCTION__, dirname, dentry->d_name);
5997             goto cleanup;
5998         }
5999         /* Ignore subdirectories and anything starting with a dot */
6000 #ifdef DT_DIR
6001         if (dentry->d_type == DT_DIR)
6002             continue;
6003 #endif
6004         if (dentry->d_name[0] == '.')
6005             continue;
6006         (void) snprintf(filename, sizeof(filename), "%s/%s", dirname, dentry->d_name);
6007 
6008         retval = load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
6009                                    id_cryptoctx, catype, filename);
6010         if (retval)
6011             goto cleanup;
6012     }
6013 
6014     retval = 0;
6015 
6016   cleanup:
6017     if (d != NULL) 
6018         (void) closedir(d);
6019 
6020     return retval;
6021 }
6022 
6023 /* ARGSUSED */
6024 krb5_error_code
6025 crypto_load_cas_and_crls(krb5_context context,
6026                          pkinit_plg_crypto_context plg_cryptoctx,
6027                          pkinit_req_crypto_context req_cryptoctx,
6028                          pkinit_identity_opts *idopts,
6029                          pkinit_identity_crypto_context id_cryptoctx,
6030                          int idtype,
6031                          int catype,
6032                          char *id) 
6033 {
6034     pkiDebug("%s: called with idtype %s and catype %s\n",
6035              __FUNCTION__, idtype2string(idtype), catype2string(catype));
6036     /* Solaris Kerberos: Removed "break"'s as they are never reached */
6037     switch (idtype) {
6038     case IDTYPE_FILE:
6039         return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
6040                                  id_cryptoctx, catype, id);
6041     case IDTYPE_DIR:
6042         return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
6043                                      id_cryptoctx, catype, id);
6044     default:
6045         return ENOTSUP;
6046     }
6047 }
6048 
6049 static krb5_error_code
6050 create_identifiers_from_stack(STACK_OF(X509) *sk,
6051                               krb5_external_principal_identifier *** ids)
6052 {
6053     krb5_error_code retval = ENOMEM;
6054     int i = 0, sk_size = sk_X509_num(sk);
6055     krb5_external_principal_identifier **krb5_cas = NULL;
6056     X509 *x = NULL;
6057     X509_NAME *xn = NULL;
6058     unsigned char *p = NULL;
6059     int len = 0;
6060     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6061     char buf[DN_BUF_LEN];
6062 
6063     *ids = NULL;
6064 
6065     krb5_cas =
6066         malloc((sk_size + 1) * sizeof(krb5_external_principal_identifier *));
6067     if (krb5_cas == NULL)
6068         return ENOMEM;
6069     krb5_cas[sk_size] = NULL;
6070 
6071     for (i = 0; i < sk_size; i++) {
6072         krb5_cas[i] = (krb5_external_principal_identifier *)malloc(sizeof(krb5_external_principal_identifier));
6073 
6074         x = sk_X509_value(sk, i);
6075 
6076         X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6077         pkiDebug("#%d cert= %s\n", i, buf);
6078 
6079         /* fill-in subjectName */
6080         krb5_cas[i]->subjectName.magic = 0;
6081         krb5_cas[i]->subjectName.length = 0;
6082         krb5_cas[i]->subjectName.data = NULL;
6083 
6084         xn = X509_get_subject_name(x);
6085         len = i2d_X509_NAME(xn, NULL);
6086         if ((p = krb5_cas[i]->subjectName.data = (unsigned char *)malloc((size_t) len)) == NULL)
6087             goto cleanup;
6088         i2d_X509_NAME(xn, &p);
6089         krb5_cas[i]->subjectName.length = len;
6090 
6091         /* fill-in issuerAndSerialNumber */
6092         krb5_cas[i]->issuerAndSerialNumber.length = 0;
6093         krb5_cas[i]->issuerAndSerialNumber.magic = 0;
6094         krb5_cas[i]->issuerAndSerialNumber.data = NULL;
6095 
6096 #ifdef LONGHORN_BETA_COMPAT
6097 if (longhorn == 0) { /* XXX Longhorn doesn't like this */
6098 #endif
6099         is = PKCS7_ISSUER_AND_SERIAL_new();
6100         X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6101         M_ASN1_INTEGER_free(is->serial);
6102         is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
6103         len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6104         if ((p = krb5_cas[i]->issuerAndSerialNumber.data =
6105              (unsigned char *)malloc((size_t) len)) == NULL)
6106             goto cleanup;
6107         i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6108         krb5_cas[i]->issuerAndSerialNumber.length = len;
6109 #ifdef LONGHORN_BETA_COMPAT
6110 }
6111 #endif
6112 
6113         /* fill-in subjectKeyIdentifier */
6114         krb5_cas[i]->subjectKeyIdentifier.length = 0;
6115         krb5_cas[i]->subjectKeyIdentifier.magic = 0;
6116         krb5_cas[i]->subjectKeyIdentifier.data = NULL;
6117 
6118 
6119 #ifdef LONGHORN_BETA_COMPAT
6120 if (longhorn == 0) {    /* XXX Longhorn doesn't like this */
6121 #endif
6122         if (X509_get_ext_by_NID(x, NID_subject_key_identifier, -1) >= 0) {
6123             ASN1_OCTET_STRING *ikeyid = NULL;
6124 
6125             if ((ikeyid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL,
6126                                            NULL))) {
6127                 len = i2d_ASN1_OCTET_STRING(ikeyid, NULL);
6128                 if ((p = krb5_cas[i]->subjectKeyIdentifier.data =
6129                         (unsigned char *)malloc((size_t) len)) == NULL)
6130                     goto cleanup;
6131                 i2d_ASN1_OCTET_STRING(ikeyid, &p);          
6132                 krb5_cas[i]->subjectKeyIdentifier.length = len;
6133             }
6134             if (ikeyid != NULL)
6135                 ASN1_OCTET_STRING_free(ikeyid);
6136         }
6137 #ifdef LONGHORN_BETA_COMPAT
6138 }
6139 #endif
6140         if (is != NULL) {
6141             if (is->issuer != NULL)
6142                 X509_NAME_free(is->issuer);
6143             if (is->serial != NULL)
6144                 ASN1_INTEGER_free(is->serial);
6145             free(is);
6146         }
6147     }
6148 
6149     *ids = krb5_cas;
6150 
6151     retval = 0;
6152   cleanup:
6153     if (retval)
6154         free_krb5_external_principal_identifier(&krb5_cas);
6155 
6156     return retval;
6157 }
6158 
6159 /* ARGSUSED */
6160 static krb5_error_code
6161 create_krb5_invalidCertificates(krb5_context context,
6162                                 pkinit_plg_crypto_context plg_cryptoctx,
6163                                 pkinit_req_crypto_context req_cryptoctx,
6164                                 pkinit_identity_crypto_context id_cryptoctx,
6165                                 krb5_external_principal_identifier *** ids)
6166 {
6167 
6168     krb5_error_code retval = ENOMEM;
6169     STACK_OF(X509) *sk = NULL;
6170 
6171     *ids = NULL;
6172     if (req_cryptoctx->received_cert == NULL)
6173         return KRB5KDC_ERR_PREAUTH_FAILED;
6174 
6175     sk = sk_X509_new_null();
6176     if (sk == NULL) 
6177         goto cleanup;
6178     sk_X509_push(sk, req_cryptoctx->received_cert);
6179 
6180     retval = create_identifiers_from_stack(sk, ids);
6181 
6182     sk_X509_free(sk);
6183 cleanup:
6184 
6185     return retval;
6186 }
6187 
6188 /* ARGSUSED */
6189 krb5_error_code
6190 create_krb5_supportedCMSTypes(krb5_context context,
6191                               pkinit_plg_crypto_context plg_cryptoctx,
6192                               pkinit_req_crypto_context req_cryptoctx,
6193                               pkinit_identity_crypto_context id_cryptoctx,
6194                               krb5_algorithm_identifier ***oids)
6195 {
6196 
6197     krb5_error_code retval = ENOMEM;
6198     krb5_algorithm_identifier **loids = NULL;
6199     krb5_octet_data des3oid = {0, 8, (unsigned char *)"\x2A\x86\x48\x86\xF7\x0D\x03\x07" };
6200 
6201     *oids = NULL;
6202     loids = malloc(2 * sizeof(krb5_algorithm_identifier *));
6203     if (loids == NULL)
6204         goto cleanup;
6205     loids[1] = NULL;
6206     loids[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
6207     if (loids[0] == NULL) {
6208         free(loids);
6209         goto cleanup;
6210     }
6211     retval = pkinit_copy_krb5_octet_data(&loids[0]->algorithm, &des3oid);
6212     if (retval) {
6213         free(loids[0]);
6214         free(loids);
6215         goto cleanup;
6216     }
6217     loids[0]->parameters.length = 0;
6218     loids[0]->parameters.data = NULL;
6219 
6220     *oids = loids;
6221     retval = 0;
6222 cleanup:
6223 
6224     return retval;
6225 }
6226 
6227 /* ARGSUSED */
6228 krb5_error_code
6229 create_krb5_trustedCertifiers(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                               krb5_external_principal_identifier *** ids)
6234 {
6235 
6236     /* Solaris Kerberos */
6237     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6238 
6239     *ids = NULL;
6240     if (id_cryptoctx->trustedCAs == NULL)
6241         return KRB5KDC_ERR_PREAUTH_FAILED;
6242 
6243     return create_identifiers_from_stack(sk, ids);
6244     
6245 }
6246 
6247 /* ARGSUSED */
6248 krb5_error_code
6249 create_krb5_trustedCas(krb5_context context,
6250                        pkinit_plg_crypto_context plg_cryptoctx,
6251                        pkinit_req_crypto_context req_cryptoctx,
6252                        pkinit_identity_crypto_context id_cryptoctx,
6253                        int flag,
6254                        krb5_trusted_ca *** ids)
6255 {
6256     krb5_error_code retval = ENOMEM;
6257     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6258     int i = 0, len = 0, sk_size = sk_X509_num(sk);
6259     krb5_trusted_ca **krb5_cas = NULL;
6260     X509 *x = NULL;
6261     char buf[DN_BUF_LEN];
6262     X509_NAME *xn = NULL;
6263     unsigned char *p = NULL;
6264     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6265 
6266     *ids = NULL;
6267     if (id_cryptoctx->trustedCAs == NULL)
6268         return KRB5KDC_ERR_PREAUTH_FAILED;
6269 
6270     krb5_cas = malloc((sk_size + 1) * sizeof(krb5_trusted_ca *));
6271     if (krb5_cas == NULL)
6272         return ENOMEM;
6273     krb5_cas[sk_size] = NULL;
6274 
6275     for (i = 0; i < sk_size; i++) {
6276         krb5_cas[i] = (krb5_trusted_ca *)malloc(sizeof(krb5_trusted_ca));
6277         if (krb5_cas[i] == NULL)
6278             goto cleanup;
6279         x = sk_X509_value(sk, i);
6280 
6281         X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6282         pkiDebug("#%d cert= %s\n", i, buf);
6283 
6284         switch (flag) {
6285             case choice_trusted_cas_principalName:
6286                 krb5_cas[i]->choice = choice_trusted_cas_principalName;
6287                 break;
6288             case choice_trusted_cas_caName:
6289                 krb5_cas[i]->choice = choice_trusted_cas_caName;
6290                 krb5_cas[i]->u.caName.data = NULL;
6291                 krb5_cas[i]->u.caName.length = 0;
6292                 xn = X509_get_subject_name(x);
6293                 len = i2d_X509_NAME(xn, NULL);
6294                 if ((p = krb5_cas[i]->u.caName.data =
6295                     (unsigned char *)malloc((size_t) len)) == NULL)
6296                     goto cleanup;
6297                 i2d_X509_NAME(xn, &p);
6298                 krb5_cas[i]->u.caName.length = len;
6299                 break;
6300             case choice_trusted_cas_issuerAndSerial:
6301                 krb5_cas[i]->choice = choice_trusted_cas_issuerAndSerial;
6302                 krb5_cas[i]->u.issuerAndSerial.data = NULL;
6303                 krb5_cas[i]->u.issuerAndSerial.length = 0;
6304                 is = PKCS7_ISSUER_AND_SERIAL_new();
6305                 X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6306                 M_ASN1_INTEGER_free(is->serial);
6307                 is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
6308                 len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6309                 if ((p = krb5_cas[i]->u.issuerAndSerial.data =
6310                     (unsigned char *)malloc((size_t) len)) == NULL)
6311                     goto cleanup;
6312                 i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6313                 krb5_cas[i]->u.issuerAndSerial.length = len;
6314                 if (is != NULL) {
6315                     if (is->issuer != NULL)
6316                         X509_NAME_free(is->issuer);
6317                     if (is->serial != NULL)
6318                         ASN1_INTEGER_free(is->serial);
6319                     free(is);
6320                 }
6321                 break;
6322             default: break;
6323         }
6324     }
6325     retval = 0;
6326     *ids = krb5_cas;
6327 cleanup:
6328     if (retval)
6329         free_krb5_trusted_ca(&krb5_cas);
6330 
6331     return retval;
6332 }
6333 
6334 /* ARGSUSED */
6335 krb5_error_code
6336 create_issuerAndSerial(krb5_context context,
6337                        pkinit_plg_crypto_context plg_cryptoctx,
6338                        pkinit_req_crypto_context req_cryptoctx,
6339                        pkinit_identity_crypto_context id_cryptoctx,
6340                        unsigned char **out,
6341                        unsigned int *out_len)
6342 {
6343     unsigned char *p = NULL;
6344     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6345     int len = 0;
6346     krb5_error_code retval = ENOMEM;
6347     X509 *cert = req_cryptoctx->received_cert;
6348 
6349     *out = NULL;
6350     *out_len = 0;
6351     if (req_cryptoctx->received_cert == NULL)
6352         return 0;
6353 
6354     is = PKCS7_ISSUER_AND_SERIAL_new();
6355     X509_NAME_set(&is->issuer, X509_get_issuer_name(cert));
6356     M_ASN1_INTEGER_free(is->serial);
6357     is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(cert));
6358     len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6359     if ((p = *out = (unsigned char *)malloc((size_t) len)) == NULL)
6360         goto cleanup;
6361     i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6362     *out_len = len;
6363     retval = 0;
6364 
6365 cleanup:
6366     X509_NAME_free(is->issuer);
6367     ASN1_INTEGER_free(is->serial);
6368     free(is);
6369 
6370     return retval;
6371 }
6372 
6373 static int
6374 pkcs7_decrypt(krb5_context context,
6375               pkinit_identity_crypto_context id_cryptoctx,
6376               PKCS7 *p7,
6377               BIO *data)
6378 {
6379     BIO *tmpmem = NULL;
6380     /* Solaris Kerberos */
6381     int i = 0;
6382     char buf[4096];
6383 
6384     if(p7 == NULL)
6385         return 0;
6386 
6387     if(!PKCS7_type_is_enveloped(p7)) {
6388         pkiDebug("wrong pkcs7 content type\n");
6389         return 0;
6390     }
6391 
6392     if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) {
6393         pkiDebug("unable to decrypt pkcs7 object\n");
6394         return 0;
6395     }
6396 /* Solaris Kerberos: Suppress sun studio compiler warning */
6397 #pragma error_messages (off, E_END_OF_LOOP_CODE_NOT_REACHED)
6398     for(;;) {
6399         i = BIO_read(tmpmem, buf, sizeof(buf));
6400         if (i <= 0) break;
6401         BIO_write(data, buf, i);
6402         BIO_free_all(tmpmem);
6403         return 1;
6404     }
6405 #pragma error_messages (default, E_END_OF_LOOP_CODE_NOT_REACHED)
6406 
6407     return 0; 
6408 }
6409 
6410 krb5_error_code
6411 pkinit_process_td_trusted_certifiers(
6412     krb5_context context,
6413     pkinit_plg_crypto_context plg_cryptoctx,
6414     pkinit_req_crypto_context req_cryptoctx,
6415     pkinit_identity_crypto_context id_cryptoctx,
6416     krb5_external_principal_identifier **krb5_trusted_certifiers,
6417     int td_type)
6418 {
6419     krb5_error_code retval = ENOMEM;
6420     STACK_OF(X509_NAME) *sk_xn = NULL;
6421     X509_NAME *xn = NULL;
6422     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6423     ASN1_OCTET_STRING *id = NULL;
6424     const unsigned char *p = NULL;
6425     char buf[DN_BUF_LEN];
6426     int i = 0;
6427 
6428     if (td_type == TD_TRUSTED_CERTIFIERS)
6429         pkiDebug("received trusted certifiers\n");
6430     else
6431         pkiDebug("received invalid certificate\n");
6432 
6433     sk_xn = sk_X509_NAME_new_null();
6434     while(krb5_trusted_certifiers[i] != NULL) {
6435         if (krb5_trusted_certifiers[i]->subjectName.data != NULL) {
6436             p = krb5_trusted_certifiers[i]->subjectName.data;
6437             xn = d2i_X509_NAME(NULL, &p,
6438                 (int)krb5_trusted_certifiers[i]->subjectName.length);
6439             if (xn == NULL)
6440                 goto cleanup;
6441             X509_NAME_oneline(xn, buf, sizeof(buf));
6442             if (td_type == TD_TRUSTED_CERTIFIERS)
6443                 pkiDebug("#%d cert = %s is trusted by kdc\n", i, buf);
6444             else
6445                 pkiDebug("#%d cert = %s is invalid\n", i, buf);
6446                 sk_X509_NAME_push(sk_xn, xn);
6447         }
6448 
6449         if (krb5_trusted_certifiers[i]->issuerAndSerialNumber.data != NULL) {
6450             p = krb5_trusted_certifiers[i]->issuerAndSerialNumber.data;
6451             is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p,
6452                 (int)krb5_trusted_certifiers[i]->issuerAndSerialNumber.length);
6453             if (is == NULL)
6454                 goto cleanup;
6455             X509_NAME_oneline(is->issuer, buf, sizeof(buf));
6456             if (td_type == TD_TRUSTED_CERTIFIERS)
6457                 pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
6458                          buf, ASN1_INTEGER_get(is->serial));
6459             else
6460                 pkiDebug("#%d issuer = %s serial = %ld is invalid\n", i, buf,
6461                          ASN1_INTEGER_get(is->serial));
6462             PKCS7_ISSUER_AND_SERIAL_free(is);
6463         }
6464 
6465         if (krb5_trusted_certifiers[i]->subjectKeyIdentifier.data != NULL) {
6466             p = krb5_trusted_certifiers[i]->subjectKeyIdentifier.data;
6467             id = d2i_ASN1_OCTET_STRING(NULL, &p,
6468                 (int)krb5_trusted_certifiers[i]->subjectKeyIdentifier.length);
6469             if (id == NULL)
6470                 goto cleanup;
6471             /* XXX */
6472             ASN1_OCTET_STRING_free(id);
6473         }
6474         i++;
6475     }
6476     /* XXX Since we not doing anything with received trusted certifiers
6477      * return an error. this is the place where we can pick a different
6478      * client certificate based on the information in td_trusted_certifiers
6479      */
6480     retval = KRB5KDC_ERR_PREAUTH_FAILED;
6481 cleanup:
6482     if (sk_xn != NULL)
6483         sk_X509_NAME_pop_free(sk_xn, X509_NAME_free);
6484 
6485     return retval;
6486 }
6487 
6488 static BIO *
6489 pkcs7_dataDecode(krb5_context context,
6490                  pkinit_identity_crypto_context id_cryptoctx,
6491                  PKCS7 *p7)
6492 {
6493     int i = 0;
6494     unsigned int jj = 0, tmp_len = 0;
6495     BIO *out=NULL,*etmp=NULL,*bio=NULL;
6496     unsigned char *tmp=NULL;
6497     ASN1_OCTET_STRING *data_body=NULL;
6498     const EVP_CIPHER *evp_cipher=NULL;
6499     EVP_CIPHER_CTX *evp_ctx=NULL;
6500     X509_ALGOR *enc_alg=NULL;
6501     STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
6502 /* Solaris Kerberos: Not used */
6503 #if 0
6504     X509_ALGOR *xalg=NULL;
6505 #endif
6506     PKCS7_RECIP_INFO *ri=NULL;
6507     X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
6508         id_cryptoctx->cert_index);
6509 
6510     p7->state=PKCS7_S_HEADER;
6511 
6512     rsk=p7->d.enveloped->recipientinfo;
6513     enc_alg=p7->d.enveloped->enc_data->algorithm;
6514     data_body=p7->d.enveloped->enc_data->enc_data;
6515     evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
6516     if (evp_cipher == NULL) {
6517         PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
6518         goto cleanup;
6519     }
6520 /* Solaris Kerberos: Not used */
6521 #if 0
6522     xalg=p7->d.enveloped->enc_data->algorithm;
6523 #endif
6524 
6525     if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
6526         PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
6527         goto cleanup;
6528     }
6529 
6530     /* It was encrypted, we need to decrypt the secret key
6531      * with the private key */
6532 
6533     /* Find the recipientInfo which matches the passed certificate
6534      * (if any)
6535      */
6536 
6537     if (cert) {
6538         for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6539             int tmp_ret = 0;
6540             ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6541             tmp_ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
6542                                     cert->cert_info->issuer);
6543             if (!tmp_ret) {
6544                 tmp_ret = M_ASN1_INTEGER_cmp(cert->cert_info->serialNumber,
6545                                              ri->issuer_and_serial->serial);
6546                 if (!tmp_ret)
6547                     break;
6548             }
6549             ri=NULL;
6550         }
6551         if (ri == NULL) {
6552             PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6553                      PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
6554             goto cleanup;
6555         }
6556         
6557     }
6558 
6559     /* If we haven't got a certificate try each ri in turn */
6560 
6561     if (cert == NULL) {
6562         for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6563             ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6564             jj = pkinit_decode_data(context, id_cryptoctx,
6565                 M_ASN1_STRING_data(ri->enc_key),
6566                 (unsigned int) M_ASN1_STRING_length(ri->enc_key),
6567                 &tmp, &tmp_len);
6568             if (jj) {
6569                 PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6570                 goto cleanup;
6571             }
6572 
6573             if (!jj && tmp_len > 0) {
6574                 jj = tmp_len;
6575                 break;
6576             }
6577 
6578             ERR_clear_error();
6579             ri = NULL;
6580         }
6581 
6582         if (ri == NULL) {
6583             PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_KEY);
6584             goto cleanup;
6585         }
6586     }
6587     else {
6588         jj = pkinit_decode_data(context, id_cryptoctx,
6589             M_ASN1_STRING_data(ri->enc_key),
6590             (unsigned int) M_ASN1_STRING_length(ri->enc_key),
6591             &tmp, &tmp_len);
6592         /* Solaris Kerberos: tmp_len is unsigned. Cannot be < 0 */
6593         if (jj || tmp_len == 0) {
6594             PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6595             goto cleanup;
6596         }
6597         jj = tmp_len;
6598     }
6599 
6600     evp_ctx=NULL;
6601     BIO_get_cipher_ctx(etmp,&evp_ctx);
6602     if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
6603         goto cleanup;
6604     if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
6605         goto cleanup;
6606 
6607     if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
6608         /* Some S/MIME clients don't use the same key
6609          * and effective key length. The key length is
6610          * determined by the size of the decrypted RSA key.
6611          */
6612         if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)jj)) {
6613             PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6614                      PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH);
6615             goto cleanup;
6616         }
6617     }
6618     if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
6619         goto cleanup;
6620 
6621     OPENSSL_cleanse(tmp,jj);
6622 
6623     if (out == NULL)
6624         out=etmp;
6625     else
6626         BIO_push(out,etmp);
6627     etmp=NULL;
6628 
6629     if (data_body->length > 0)
6630         bio = BIO_new_mem_buf(data_body->data, data_body->length);
6631     else {
6632         bio=BIO_new(BIO_s_mem());
6633         BIO_set_mem_eof_return(bio,0);
6634     }
6635     BIO_push(out,bio);
6636     bio=NULL;
6637 
6638     /* Solaris Kerberos */
6639     goto out;
6640 
6641 cleanup:
6642         if (out != NULL) BIO_free_all(out);
6643         if (etmp != NULL) BIO_free_all(etmp);
6644         if (bio != NULL) BIO_free_all(bio);
6645         out=NULL;
6646 
6647 out:
6648     if (tmp != NULL)
6649         free(tmp);
6650 
6651     return(out);
6652 }
6653 
6654 static krb5_error_code
6655 der_decode_data(unsigned char *data, long data_len,
6656                 unsigned char **out, long *out_len)
6657 {
6658     /* Solaris Kerberos */
6659     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
6660     ASN1_OCTET_STRING *s = NULL;
6661     const unsigned char *p = data;
6662 
6663     if ((s = d2i_ASN1_BIT_STRING(NULL, &p, data_len)) == NULL)
6664         goto cleanup;
6665     *out_len = s->length;
6666     if ((*out = (unsigned char *) malloc((size_t) *out_len + 1)) == NULL) {
6667         retval = ENOMEM;
6668         goto cleanup;
6669     }
6670     (void) memcpy(*out, s->data, (size_t) s->length);
6671     (*out)[s->length] = '\0';
6672 
6673     retval = 0;
6674   cleanup:
6675     if (s != NULL)
6676         ASN1_OCTET_STRING_free(s);
6677 
6678     return retval;
6679 }
6680 
6681 
6682 #ifdef DEBUG_DH
6683 static void
6684 print_dh(DH * dh, char *msg)
6685 {
6686     BIO *bio_err = NULL;
6687 
6688     bio_err = BIO_new(BIO_s_file());
6689     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6690 
6691     if (msg)
6692         BIO_puts(bio_err, (const char *)msg);
6693     if (dh)
6694         DHparams_print(bio_err, dh);
6695 
6696     BN_print(bio_err, dh->q);
6697     BIO_puts(bio_err, (const char *)"\n");
6698     BIO_free(bio_err);
6699 
6700 }
6701 
6702 static void
6703 print_pubkey(BIGNUM * key, char *msg)
6704 {
6705     BIO *bio_err = NULL;
6706 
6707     bio_err = BIO_new(BIO_s_file());
6708     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6709 
6710     if (msg)
6711         BIO_puts(bio_err, (const char *)msg);
6712     if (key)
6713         BN_print(bio_err, key);
6714     BIO_puts(bio_err, "\n");
6715 
6716     BIO_free(bio_err);
6717 
6718 }
6719 #endif
6720 
6721 /*
6722  * Solaris Kerberos:
6723  * Error message generation has changed so gettext() can be used
6724  */
6725 #if 0
6726 static char *
6727 pkinit_pkcs11_code_to_text(int err)
6728 {
6729     int i;
6730     static char uc[64];
6731 
6732     for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
6733         if (pkcs11_errstrings[i].code == err)
6734             break;
6735     if (pkcs11_errstrings[i].text != NULL)
6736         return (pkcs11_errstrings[i].text);
6737     snprintf(uc, 64, gettext("unknown code 0x%x"), err);
6738     return (uc);
6739 }
6740 #endif
6741 
6742 static char *
6743 pkinit_pkcs11_code_to_text(int err) {
6744         return pkcs11_error_table(err);
6745 }