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