/*
* COPYRIGHT (C) 2006,2007
* THE REGENTS OF THE UNIVERSITY OF MICHIGAN
* ALL RIGHTS RESERVED
*
* Permission is granted to use, copy, create derivative works
* and redistribute this software and such derivative works
* for any purpose, so long as the name of The University of
* Michigan is not used in any advertising or publicity
* pertaining to the use of distribution of this software
* without specific, written prior authorization. If the
* above copyright notice or any other identification of the
* University of Michigan is included in any copy of any
* portion of this software, then the disclaimer below must
* also be included.
*
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
* FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
* PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
* MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
* WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
* REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
* FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
* OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGES.
*/
/*
* Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <unistd.h>
#include <dirent.h>
/* Solaris Kerberos */
#include <libintl.h>
#include <assert.h>
#include <security/pam_appl.h>
#include <ctype.h>
#include "k5-int.h"
#include <ctype.h>
/*
* Q: What is this SILLYDECRYPT stuff about?
* A: When using the ActivCard Linux pkcs11 library (v2.0.1),
* the decrypt function fails. By inserting an extra
* function call, which serves nothing but to change the
* stack, we were able to work around the issue. If the
* ActivCard library is fixed in the future, this
* definition and related code can be removed.
*/
#define SILLYDECRYPT
#include "pkinit_crypto_openssl.h"
/*
* Solaris Kerberos:
* Changed to a switch statement so gettext() can be used
* for internationization.
* Use defined constants rather than raw numbers for error codes.
*/
static char *
switch (code) {
case CKR_OK:
return (gettext("ok"));
case CKR_CANCEL:
return (gettext("cancel"));
case CKR_HOST_MEMORY:
return (gettext("host memory"));
case CKR_SLOT_ID_INVALID:
return (gettext("slot id invalid"));
case CKR_GENERAL_ERROR:
return (gettext("general error"));
case CKR_FUNCTION_FAILED:
return (gettext("function failed"));
case CKR_ARGUMENTS_BAD:
return (gettext("arguments bad"));
case CKR_NO_EVENT:
return (gettext("no event"));
return (gettext("need to create threads"));
case CKR_CANT_LOCK:
return (gettext("cant lock"));
case CKR_ATTRIBUTE_READ_ONLY:
return (gettext("attribute read only"));
case CKR_ATTRIBUTE_SENSITIVE:
return (gettext("attribute sensitive"));
return (gettext("attribute type invalid"));
return (gettext("attribute value invalid"));
case CKR_DATA_INVALID:
return (gettext("data invalid"));
case CKR_DATA_LEN_RANGE:
return (gettext("data len range"));
case CKR_DEVICE_ERROR:
return (gettext("device error"));
case CKR_DEVICE_MEMORY:
return (gettext("device memory"));
case CKR_DEVICE_REMOVED:
return (gettext("device removed"));
return (gettext("encrypted data invalid"));
return (gettext("encrypted data len range"));
case CKR_FUNCTION_CANCELED:
return (gettext("function canceled"));
return (gettext("function not parallel"));
return (gettext("function not supported"));
case CKR_KEY_HANDLE_INVALID:
return (gettext("key handle invalid"));
case CKR_KEY_SIZE_RANGE:
return (gettext("key size range"));
return (gettext("key type inconsistent"));
case CKR_KEY_NOT_NEEDED:
return (gettext("key not needed"));
case CKR_KEY_CHANGED:
return (gettext("key changed"));
case CKR_KEY_NEEDED:
return (gettext("key needed"));
case CKR_KEY_INDIGESTIBLE:
return (gettext("key indigestible"));
return (gettext("key function not permitted"));
case CKR_KEY_NOT_WRAPPABLE:
return (gettext("key not wrappable"));
case CKR_KEY_UNEXTRACTABLE:
return (gettext("key unextractable"));
case CKR_MECHANISM_INVALID:
return (gettext("mechanism invalid"));
return (gettext("mechanism param invalid"));
return (gettext("object handle invalid"));
case CKR_OPERATION_ACTIVE:
return (gettext("operation active"));
return (gettext("operation not initialized"));
case CKR_PIN_INCORRECT:
return (gettext("pin incorrect"));
case CKR_PIN_INVALID:
return (gettext("pin invalid"));
case CKR_PIN_LEN_RANGE:
return (gettext("pin len range"));
case CKR_PIN_EXPIRED:
return (gettext("pin expired"));
case CKR_PIN_LOCKED:
return (gettext("pin locked"));
case CKR_SESSION_CLOSED:
return (gettext("session closed"));
case CKR_SESSION_COUNT:
return (gettext("session count"));
return (gettext("session handle invalid"));
return (gettext("session parallel not supported"));
case CKR_SESSION_READ_ONLY:
return (gettext("session read only"));
case CKR_SESSION_EXISTS:
return (gettext("session exists"));
return (gettext("session read only exists"));
return (gettext("session read write so exists"));
case CKR_SIGNATURE_INVALID:
return (gettext("signature invalid"));
case CKR_SIGNATURE_LEN_RANGE:
return (gettext("signature len range"));
case CKR_TEMPLATE_INCOMPLETE:
return (gettext("template incomplete"));
return (gettext("template inconsistent"));
case CKR_TOKEN_NOT_PRESENT:
return (gettext("token not present"));
case CKR_TOKEN_NOT_RECOGNIZED:
return (gettext("token not recognized"));
return (gettext("token write protected"));
return (gettext("unwrapping key handle invalid"));
return (gettext("unwrapping key size range"));
return (gettext("unwrapping key type inconsistent"));
return (gettext("user already logged in"));
case CKR_USER_NOT_LOGGED_IN:
return (gettext("user not logged in"));
return (gettext("user pin not initialized"));
case CKR_USER_TYPE_INVALID:
return (gettext("user type invalid"));
return (gettext("user another already logged in"));
case CKR_USER_TOO_MANY_TYPES:
return (gettext("user too many types"));
case CKR_WRAPPED_KEY_INVALID:
return (gettext("wrapped key invalid"));
return (gettext("wrapped key len range"));
return (gettext("wrapping key handle invalid"));
return (gettext("wrapping key size range"));
return (gettext("wrapping key type inconsistent"));
return (gettext("random seed not supported"));
case CKR_RANDOM_NO_RNG:
return (gettext("random no rng"));
return (gettext("domain params invalid"));
case CKR_BUFFER_TOO_SMALL:
return (gettext("buffer too small"));
case CKR_SAVED_STATE_INVALID:
return (gettext("saved state invalid"));
return (gettext("information sensitive"));
case CKR_STATE_UNSAVEABLE:
return (gettext("state unsaveable"));
return (gettext("cryptoki not initialized"));
return (gettext("cryptoki already initialized"));
case CKR_MUTEX_BAD:
return (gettext("mutex bad"));
case CKR_MUTEX_NOT_LOCKED:
return (gettext("mutex not locked"));
case CKR_FUNCTION_REJECTED:
return (gettext("function rejected"));
default:
return (gettext("unknown error"));
}
}
/* DH parameters */
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* Solaris Kerberos */
static int pkinit_oids_refs = 0;
/* initialize openssl routines */
/* Solaris Kerberos */
retval = openssl_init();
if (retval != 0)
goto out;
goto out;
pkiDebug("%s: initializing openssl crypto context at %p\n",
__FUNCTION__, ctx);
if (retval)
goto out;
if (retval)
goto out;
out:
return retval;
}
void
{
return;
}
{
goto out;
if (retval)
goto out;
if (retval)
goto out;
out:
if (retval) {
if (ctx)
}
return retval;
}
void
{
return;
}
{
/* Solaris Kerberos */
return EINVAL;
return ENOMEM;
return 0;
}
void
{
if (req_cryptoctx == NULL)
return;
}
static krb5_error_code
{
int nid = 0;
/*
* If OpenSSL already knows about the OID, use the
* existing definition. Otherwise, create an OID object.
*/
goto out; \
} \
} \
/* Solaris Kerberos */
if (retval != 0)
goto out;
"id-pkinit-san", "KRB5PrincipalName");
"id-pkinit-authdata", "PKINIT signedAuthPack");
"id-pkinit-DHKeyData", "PKINIT dhSignedData");
"id-pkinit-rkeyData", "PKINIT encKeyPack");
"id-pkinit-KPClientAuth", "PKINIT Client EKU");
"id-pkinit-KPKdc", "KDC EKU");
#if 0
"id-pkcs7-data", "PKCS7 data");
#else
/* See note in pkinit_pkcs7type2oid() */
#endif
"id-ms-kp-sc-logon EKU", "Microsoft SmartCard Login EKU");
"id-ms-san-upn", "Microsoft Universal Principal Name");
"id-kp-serverAuth EKU", "Server Authentication EKU");
/* Success */
retval = 0;
/* Solaris Kerberos */
out:
return retval;
}
static krb5_error_code
{
int code;
return EINVAL;
return ENOMEM;
if (code == 0) {
goto cleanup;
}
goto cleanup;
}
retval = 0;
return retval;
}
static krb5_error_code
{
int code;
return EINVAL;
return ENOMEM;
if (code == 0) {
goto cleanup;
}
goto cleanup;
}
retval = 0;
return retval;
}
static void
{
return;
/* Only call OBJ_cleanup once! */
/* Solaris Kerberos: locking */
if (--pkinit_oids_refs == 0)
OBJ_cleanup();
}
static krb5_error_code
{
goto cleanup;
sizeof(pkinit_1024_dhprime), NULL);
goto cleanup;
goto cleanup;
sizeof(pkinit_2048_dhprime), NULL);
goto cleanup;
goto cleanup;
sizeof(pkinit_4096_dhprime), NULL);
goto cleanup;
retval = 0;
if (retval)
return retval;
}
static void
{
}
static krb5_error_code
{
/* Solaris Kerberos */
int i;
for (i = 0; i < MAX_CREDS_ALLOWED; i++)
ctx->cert_index = 0;
return 0;
}
static void
{
return;
}
static krb5_error_code
{
/* Solaris Kerberos */
#ifndef WITHOUT_PKCS11
return ENOMEM;
#endif
ctx->pkcs11_method = 0;
return 0;
}
static void
{
#ifndef WITHOUT_PKCS11
return;
}
/*
* Solaris Kerberos:
* Only call C_Finalize if the process was not already using pkcs11.
*/
}
}
}
#endif
}
void *prompter_data)
{
return 0;
}
/* ARGSUSED */
int cms_msg_type,
int include_certchain,
unsigned char *data,
unsigned int data_len,
unsigned char **signed_data,
unsigned int *signed_data_len)
{
/* Solaris Kerberos */
unsigned char *p;
unsigned int sig_len = 0;
/* Solaris Kerberos */
if (signed_data == NULL)
return EINVAL;
if (signed_data_len == NULL)
return EINVAL;
/* start creating PKCS7 data */
goto cleanup;
goto cleanup;
goto cleanup;
/* create a cert chain that has at least the signer's certificate */
goto cleanup;
if (!include_certchain) {
pkiDebug("only including signer's certificate\n");
} else {
/* create a cert chain */
int i = 0, size = 0;
goto cleanup;
pkiDebug("building certificate chain\n");
/* Solaris Kerberos */
if (X509_verify_cert(&certctx) <= 0) {
pkiDebug("failed to create a certificate chain: %s\n",
pkiDebug("No trusted CAs found. Check your X509_anchors\n");
goto cleanup;
}
for(i = 0; i < size - 1; i++) {
}
}
/* fill-in PKCS7_SIGNER_INFO */
goto cleanup;
goto cleanup;
goto cleanup;
/* because ASN1_INTEGER_set is used to set a 'long' we will do
* things the ugly way. */
goto cleanup;
/* will not fill-out EVP_PKEY because it's on the smartcard */
/* Set digest algs */
goto cleanup;
/* Set sig algs */
goto cleanup;
/* pick the correct oid for the eContentInfo */
goto cleanup;
if (cms_msg_type == CMS_SIGN_DRAFT9) {
/* don't include signed attributes for pa-type 15 request */
} else {
/* add signed attributes */
/* compute sha1 digest over the EncapsulatedContentInfo */
/* create a message digest attr */
V_ASN1_OCTET_STRING, (char *) digest_attr);
/* create a content-type attr */
V_ASN1_OBJECT, oid);
/* create the signature over signed attributes. get DER encoded value */
/* This is the place where smartcard signature needs to be calculated */
goto cleanup2;
}
#ifndef WITHOUT_PKCS11
/* Some tokens can only do RSAEncryption without sha1 hash */
/* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
* function and the hash value into an ASN.1 value of type DigestInfo
* DigestInfo::=SEQUENCE {
* digestAlgorithm AlgorithmIdentifier,
* digest OCTET STRING }
*/
pkiDebug("mech = CKM_RSA_PKCS\n");
/* if this is not draft9 request, include digest signed attribute */
if (cms_msg_type != CMS_SIGN_DRAFT9)
else
alg = X509_ALGOR_new();
goto cleanup2;
goto cleanup2;
goto cleanup2;
if (digest_buf == NULL)
goto cleanup2;
if (digestInfo_buf == NULL)
goto cleanup2;
i2d_X509_ALGOR(alg, &y);
i2d_ASN1_OCTET_STRING(digest, &y);
#ifdef DEBUG_SIG
pkiDebug("signing buffer\n");
#endif
} else
#endif
{
pkiDebug("mech = %s\n",
}
#ifdef DEBUG_SIG
#endif
if (cms_msg_type != CMS_SIGN_DRAFT9)
if (retval)
goto cleanup2;
/* Add signature */
(int)sig_len)) {
pkiDebug("failed to add a signed digest attribute\n");
goto cleanup2;
}
/* adder signer_info to pkcs7 signed */
goto cleanup2;
/* start on adding data to the pkcs7 signed */
goto cleanup2;
goto cleanup2;
goto cleanup2;
(int)data_len)) {
pkiDebug("failed to add pkcs7 data\n");
goto cleanup2;
}
goto cleanup2;
if (!(*signed_data_len)) {
pkiDebug("failed to der encode pkcs7\n");
goto cleanup2;
}
if ((p = *signed_data =
goto cleanup2;
/* DER encode PKCS7 data */
if (!retval) {
pkiDebug("failed to der encode pkcs7\n");
goto cleanup2;
}
retval = 0;
#ifdef DEBUG_ASN1
if (cms_msg_type == CMS_SIGN_CLIENT) {
} else {
if (cms_msg_type == CMS_SIGN_SERVER) {
"/tmp/kdc_pkcs7_signeddata");
} else {
}
}
#endif
if (cms_msg_type != CMS_SIGN_DRAFT9)
#ifndef WITHOUT_PKCS11
if (digest_buf != NULL)
if (digestInfo_buf != NULL)
}
#endif
PKCS7_free(p7);
return retval;
}
int cms_msg_type,
int require_crl_checking,
unsigned char *signed_data,
unsigned int signed_data_len,
unsigned char **data,
unsigned int *data_len,
unsigned char **authz_data,
unsigned int *authz_data_len)
{
const unsigned char *p = signed_data;
#ifdef DEBUG_ASN1
#endif
/* Do this early enough to create the shadow OID for pkcs7-data if needed */
goto cleanup;
/* decode received PKCS7 message */
pkiDebug("%s: failed to decode message: %s\n",
goto cleanup;
}
/* verify that the received message is PKCS7 SignedData message */
pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
goto cleanup;
}
/* setup to verify X509 certificate used to sign PKCS7 message */
if (!(store = X509_STORE_new()))
goto cleanup;
/* check if we are inforcing CRL checking */
if (require_crl_checking)
else
/* get the signer's information from the PKCS7 message */
goto cleanup;
goto cleanup;
goto cleanup;
/* create available CRL information (get local CRLs and include CRLs
* received in the PKCS7 message
*/
else {
for (i = 0; i < size; i++)
for (i = 0; i < size; i++)
}
/* create available intermediate CAs chains (get local intermediateCAs and
* include the CA chain received in the PKCS7 message
*/
else {
for (i = 0; i < size; i++) {
}
for (i = 0; i < size; i++) {
}
}
/* initialize x509 context with the received certificate and
* trusted and intermediate CA chains and CRLs
*/
goto cleanup;
/* add trusted CAs certificates for cert verification */
else {
pkiDebug("unable to find any trusted CAs\n");
goto cleanup;
}
#ifdef DEBUG_CERTCHAIN
if (intermediateCAs != NULL) {
for (i = 0; i < size; i++) {
}
}
for (i = 0; i < size; i++) {
}
}
for (i = 0; i < size; i++) {
}
}
#endif
i = X509_verify_cert(&cert_ctx);
if (i <= 0) {
int j = X509_STORE_CTX_get_error(&cert_ctx);
switch(j) {
case X509_V_ERR_CERT_REVOKED:
break;
break;
break;
default:
}
#ifdef DEBUG_CERTCHAIN
for (j = 0; j < size; j++) {
}
#endif
} else {
/* retrieve verified certificate chain */
}
if (i <= 0)
goto cleanup;
if (cms_msg_type == CMS_SIGN_DRAFT9)
flags |= PKCS7_NOATTR;
int valid_oid = 0;
valid_oid = 1;
else if (cms_msg_type == CMS_SIGN_DRAFT9) {
/*
* Various implementations of the pa-type 15 request use
* different OIDS. We check that the returned object
* has any of the acceptable OIDs
*/
valid_oid = 1;
}
if (valid_oid)
pkiDebug("PKCS7 Verification successful\n");
else {
pkiDebug("wrong oid in eContentType\n");
goto cleanup;
}
}
else {
switch(ERR_GET_REASON(err)) {
case PKCS7_R_DIGEST_FAILURE:
break;
default:
}
pkiDebug("PKCS7 Verification failure\n");
goto cleanup;
}
/* transfer the data from PKCS7 message into return buffer */
for (size = 0;;) {
goto cleanup;
if (i <= 0)
break;
else
size += i;
}
/* generate authorization data */
goto out;
*authz_data = NULL;
if (retval) {
pkiDebug("create_identifiers_from_stack failed\n");
goto cleanup;
}
retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_verified_chain, &authz);
if (retval) {
pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
goto cleanup;
}
#ifdef DEBUG_ASN1
#endif
if (*authz_data == NULL) {
goto cleanup;
}
}
out:
retval = 0;
PKCS7_free(p7);
}
if (verified_chain != NULL)
if (krb5_verified_chain != NULL)
return retval;
}
int include_certchain,
unsigned char *key_pack,
unsigned int key_pack_len,
unsigned char **out,
unsigned int *out_len)
{
/* Solaris Kerberos */
int cms_msg_type;
/* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */
switch ((int)pa_type) {
break;
case KRB5_PADATA_PK_AS_REQ:
break;
default:
/* Solaris Kerberos */
goto cleanup;
}
&signed_data, (unsigned int *)&signed_data_len);
if (retval) {
pkiDebug("failed to create pkcs7 signed data\n");
goto cleanup;
}
/* check we have client's certificate */
goto cleanup;
}
encerts = sk_X509_new_null();
cipher = EVP_des_ede3_cbc();
switch (pa_type) {
case KRB5_PADATA_PK_AS_REQ:
&enc_data_len);
if (retval != enc_data_len) {
goto cleanup;
}
break;
if (retval != signed_data_len) {
/* Solaris Kerberos */
goto cleanup;
}
break;
default:
retval = -1;
goto cleanup;
}
pkiDebug("failed to encrypt PKCS7 object\n");
retval = -1;
goto cleanup;
}
switch (pa_type) {
case KRB5_PADATA_PK_AS_REQ:
break;
break;
}
goto cleanup;
}
if (!retval) {
pkiDebug("unable to write pkcs7 object\n");
goto cleanup;
}
retval = 0;
#ifdef DEBUG_ASN1
#endif
PKCS7_free(p7);
if (signed_data != NULL)
return retval;
}
int require_crl_checking,
unsigned char *enveloped_data,
unsigned int enveloped_data_len,
unsigned char **data,
unsigned int *data_len)
{
int i = 0;
unsigned int size = 0;
const unsigned char *p = enveloped_data;
int msg_type = 0;
#ifdef DEBUG_ASN1
"/tmp/client_envelopeddata");
#endif
/* decode received PKCS7 message */
pkiDebug("failed to decode pkcs7\n");
goto cleanup;
}
/* verify that the received message is PKCS7 EnvelopedData message */
pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n",
goto cleanup;
}
/* decrypt received PKCS7 message */
pkiDebug("PKCS7 decryption successful\n");
} else {
if (err != 0)
pkiDebug("PKCS7 decryption failed\n");
goto cleanup;
}
/* transfer the decoded PKCS7 SignedData message into a separate buffer */
for (;;) {
goto cleanup;
if (i <= 0)
break;
else
size += i;
}
tmp_buf_len = size;
#ifdef DEBUG_ASN1
#endif
/* verify PKCS7 SignedData message */
switch (pa_type) {
case KRB5_PADATA_PK_AS_REP:
break;
break;
default:
goto cleanup;
}
/*
* If this is the RFC style, wrap the signed data to make
* decoding easier in the verify routine.
* For draft9-compatible, we don't do anything because it
* is already wrapped.
*/
#ifdef LONGHORN_BETA_COMPAT
/*
* The Longhorn server returns the expected RFC-style data, but
* it is missing the sequence tag and length, so it requires
* special processing when wrapping.
* This will hopefully be fixed before the final release and
* this can all be removed.
*/
if (retval) {
pkiDebug("failed to encode signeddata\n");
goto cleanup;
}
} else {
}
#else
if (msg_type == CMS_ENVEL_SERVER) {
&tmp_buf2, &tmp_buf2_len);
if (retval) {
pkiDebug("failed to encode signeddata\n");
goto cleanup;
}
} else {
}
#endif
#ifdef DEBUG_ASN1
#endif
if (!retval)
pkiDebug("PKCS7 Verification Success\n");
else {
pkiDebug("PKCS7 Verification Failure\n");
goto cleanup;
}
retval = 0;
PKCS7_free(p7);
return retval;
}
/* ARGSUSED */
static krb5_error_code
unsigned char ***dns_ret)
{
int p = 0, u = 0, d = 0;
int i, num_found = 0;
return retval;
}
return retval;
}
int ret = 0;
unsigned int num_sans = 0;
pkiDebug("%s: found no subject alt name extensions\n",
goto cleanup;
}
pkiDebug("%s: found %d subject alt name extension(s)\n",
/* OK, we're likely returning something. Allocate return values */
if (princs_ret != NULL) {
goto cleanup;
}
}
goto cleanup;
}
}
goto cleanup;
}
}
for (i = 0; i < num_sans; i++) {
case GEN_OTHERNAME:
#ifdef DEBUG_ASN1
"/tmp/pkinit_san");
#endif
if (ret) {
pkiDebug("%s: failed decoding pkinit san value\n",
} else {
p++;
num_found++;
}
if (ret) {
pkiDebug("%s: failed parsing ms-upn san value\n",
} else {
u++;
num_found++;
}
} else {
pkiDebug("%s: unrecognized othername oid in SAN\n",
continue;
}
break;
case GEN_DNS:
pkiDebug("%s: found dns name = %s\n",
dnss[d] = (unsigned char *)
pkiDebug("%s: failed to duplicate dns name\n",
} else {
d++;
num_found++;
}
}
break;
default:
pkiDebug("%s: SAN type = %d expecting %d\n",
}
}
}
retval = 0;
if (princs)
*princs_ret = princs;
if (upns)
if (dnss)
if (retval) {
}
}
}
}
return retval;
}
/* ARGSUSED */
unsigned char ***dns_ret)
{
return retval;
}
}
/* ARGSUSED */
int checking_kdc_cert,
int *valid_eku)
{
int found_eku = 0;
int i;
/* Solaris Kerberos */
return retval;
*valid_eku = 0;
goto cleanup;
NID_ext_key_usage, -1)) >= 0) {
if (extusage) {
pkiDebug("%s: checking eku %d of %d, allow_secondary = %d\n",
if (checking_kdc_cert) {
found_eku = 1;
} else {
found_eku = 1;
}
}
}
if (found_eku) {
/* check that digitalSignature KeyUsage is present */
pkiDebug("%s: found digitalSignature KU\n",
*valid_eku = 1;
} else
pkiDebug("%s: didn't find digitalSignature KU\n",
}
}
}
retval = 0;
pkiDebug("%s: returning retval %d, valid_eku %d\n",
return retval;
}
unsigned char *key,
unsigned int dh_key_len,
{
unsigned char counter;
goto cleanup;
}
counter = 0;
offset = 0;
do {
SHA_CTX c;
SHA1_Init(&c);
SHA1_Final(md, &c);
else
counter++;
} while (offset < dh_key_len);
/* Solaris Kerberos */
if (retval)
goto cleanup;
goto cleanup;
}
}
return retval;
}
/* ARGSUSED */
int dh_size,
unsigned char **dh_params,
unsigned int *dh_params_len,
unsigned char **dh_pubkey,
unsigned int *dh_pubkey_len)
{
int dh_err = 0;
goto cleanup;
goto cleanup;
switch(dh_size) {
case 1024:
pkiDebug("client uses 1024 DH keys\n");
break;
case 2048:
pkiDebug("client uses 2048 DH keys\n");
sizeof(pkinit_2048_dhprime), NULL);
break;
case 4096:
pkiDebug("client uses 4096 DH keys\n");
sizeof(pkinit_4096_dhprime), NULL);
break;
default:
goto cleanup;
}
}
/* Solaris Kerberos */
#ifdef DEBUG
if (dh_err != 0) {
if (dh_err & DH_CHECK_P_NOT_PRIME)
pkiDebug("p value is not prime\n");
if (dh_err & DH_CHECK_P_NOT_SAFE_PRIME)
pkiDebug("p value is not a safe prime\n");
pkiDebug("unable to check the generator value\n");
if (dh_err & DH_NOT_SUITABLE_GENERATOR)
pkiDebug("the g value is not a generator\n");
}
#endif
#ifdef DEBUG_DH
#endif
if (dh_err != 0) {
goto cleanup;
}
/* pack DHparams */
/* aglo: usually we could just call i2d_DHparams to encode DH params
* however, PKINIT requires RFC3279 encoding and openssl does pkcs#3.
*/
if (retval)
goto cleanup;
/* pack DH public key */
/* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
* encoding shall be used as the contents (the value) of the
* subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
* data element
*/
goto cleanup;
goto cleanup;
}
retval = 0;
return retval;
return retval;
}
/* ARGSUSED */
unsigned char *subjectPublicKey_data,
unsigned int subjectPublicKey_length,
unsigned char **client_key,
unsigned int *client_key_len)
{
/* Solaris Kerberos */
const unsigned char *p = NULL;
long data_len;
/* decode subjectPublicKey (retrieve INTEGER from OCTET_STRING) */
pkiDebug("failed to decode subjectPublicKey\n");
/* Solaris Kerberos */
goto cleanup;
}
if ((*client_key = (unsigned char *)
goto cleanup;
}
p = data;
goto cleanup;
goto cleanup;
#ifdef DEBUG_DH
#endif
retval = 0;
if (server_pub_key != NULL)
return retval;
if (*client_key != NULL)
free(*client_key);
*client_key = NULL;
return retval;
}
/* ARGSUSED */
int minbits)
{
int dh_prime_bits;
pkiDebug("failed to decode dhparams\n");
goto cleanup;
}
/* KDC SHOULD check to see if the key parameters satisfy its policy */
pkiDebug("client sent dh params with %d bits, we require %d\n",
goto cleanup;
}
/* check dhparams is group 2 */
retval = 0;
goto cleanup;
}
/* check dhparams is group 14 */
retval = 0;
goto cleanup;
}
/* check dhparams is group 16 */
retval = 0;
goto cleanup;
}
if (retval == 0)
else
return retval;
}
/* kdc's dh function */
/* ARGSUSED */
unsigned char *data,
unsigned int data_len,
unsigned char **dh_pubkey,
unsigned int *dh_pubkey_len,
unsigned char **server_key,
unsigned int *server_key_len)
{
/* Solaris Kerberos */
unsigned char *p = NULL;
/* get client's received DH parameters that we saved in server_check_dh */
goto cleanup;
/* decode client's public key */
p = data;
goto cleanup;
goto cleanup;
if (!DH_generate_key(dh_server))
goto cleanup;
/* generate DH session key */
goto cleanup;
#ifdef DEBUG_DH
pkiDebug("server secret key=");
#endif
/* KDC reply */
/* pack DH public key */
/* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
* encoding shall be used as the contents (the value) of the
* subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
* data element
*/
goto cleanup;
goto cleanup;
i2d_ASN1_INTEGER(pub_key, &p);
retval = 0;
return retval;
if (*server_key != NULL)
free(*server_key);
return retval;
}
/*
* Solaris Kerberos:
* Add locking around did_init to make it MT-safe.
*/
static krb5_error_code
{
static int did_init = 0;
if (ret == 0) {
if (!did_init) {
/* initialize openssl routines */
did_init++;
}
}
return (ret);
}
static krb5_error_code
{
int bufsize = 0, r = 0;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
*buf_len = r;
retval = 0;
return retval;
}
static DH *
{
return NULL;
else {
if ((*a)->p == NULL)
return NULL;
}
}
return NULL;
else {
if ((*a)->g == NULL)
return NULL;
}
}
return NULL;
else {
if ((*a)->q == NULL)
return NULL;
}
}
M_ASN1_D2I_Finish(a, DH_free, 0);
}
static krb5_error_code
int type,
{
switch(type) {
case TD_TRUSTED_CERTIFIERS:
if (retval) {
pkiDebug("create_krb5_trustedCertifiers failed\n");
goto cleanup;
}
break;
case TD_INVALID_CERTIFICATES:
if (retval) {
pkiDebug("create_krb5_invalidCertificates failed\n");
goto cleanup;
}
break;
default:
retval = -1;
goto cleanup;
}
retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_trusted_certifiers, &td_certifiers);
if (retval) {
pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
goto cleanup;
}
#ifdef DEBUG_ASN1
#endif
if (typed_data == NULL) {
goto cleanup;
}
if (typed_data[0] == NULL) {
goto cleanup;
}
&data);
if (retval) {
pkiDebug("encode_krb5_typed_data failed\n");
goto cleanup;
}
#ifdef DEBUG_ASN1
#endif
retval = 0;
if (krb5_trusted_certifiers != NULL)
}
if (td_certifiers != NULL)
if (typed_data != NULL)
return retval;
}
{
return retval;
}
{
return retval;
}
/* ARGSUSED */
{
/* Solaris Kerberos */
/* Solaris Kerberos */
goto cleanup;
}
if (retval)
goto cleanup;
}
if (retval)
goto cleanup;
}
if (retval)
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
}
retval = k5int_encode_krb5_td_dh_parameters((const krb5_algorithm_identifier **)algId, &encoded_algId);
if (retval)
goto cleanup;
#ifdef DEBUG_ASN1
#endif
if (typed_data == NULL) {
goto cleanup;
}
if (typed_data == NULL) {
goto cleanup;
}
&data);
if (retval) {
pkiDebug("encode_krb5_typed_data failed\n");
goto cleanup;
}
#ifdef DEBUG_ASN1
#endif
goto cleanup;
goto cleanup;
}
retval = 0;
}
if (typed_data != NULL)
if (encoded_algId != NULL)
i++;
}
}
return retval;
}
/* ARGSUSED */
unsigned char *pdid_buf,
unsigned int pkid_len,
int *valid_kdcPkId)
{
const unsigned char *p = pdid_buf;
*valid_kdcPkId = 0;
pkiDebug("found kdcPkId in AS REQ\n");
goto cleanup;
if (!status) {
if (!status)
*valid_kdcPkId = 1;
}
retval = 0;
return retval;
}
static int
{
/* Solaris Kerberos */
retval = 0;
} else
pkiDebug("bad group 2 q dhparameter\n");
} else
pkiDebug("bad g dhparameter\n");
} else
pkiDebug("p is not well-known group 2 dhparameter\n");
return retval;
}
/* ARGSUSED */
int *new_dh_size)
{
pkiDebug("dh parameters\n");
int dh_prime_bits = 0;
goto cleanup;
pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
switch(dh_prime_bits) {
case 1024:
*new_dh_size = 1024;
ok = 1;
}
break;
case 2048:
*new_dh_size = 2048;
ok = 1;
}
break;
case 4096:
*new_dh_size = 4096;
ok = 1;
}
break;
default:
break;
}
if (!ok) {
if (retval != 0) {
pkiDebug("DH parameters provided by server are unacceptable\n");
}
else {
use_sent_dh = 1;
ok = 1;
}
}
if (!use_sent_dh)
if (ok) {
}
if (use_sent_dh)
break;
}
i++;
}
if (ok)
retval = 0;
return retval;
}
/* ARGSUSED */
static int
{
#ifdef DEBUG
if (!ok) {
}
#endif
return ok;
}
static int
{
if (!ok) {
return 1;
default:
return 0;
}
}
return ok;
}
static ASN1_OBJECT *
{
int nid;
switch (pkcs7_type) {
case CMS_SIGN_CLIENT:
return cryptoctx->id_pkinit_authData;
case CMS_SIGN_DRAFT9:
/*
* Delay creating this OID until we know we need it.
* It shadows an existing OpenSSL oid. If it
* is created too early, it breaks things like
* the use of pkcs12 (which uses pkcs7 structures).
* We need this shadow version because our code
* depends on the "other" type to be unknown to the
* OpenSSL code.
*/
pkiDebug("%s: Creating shadow instance of pkcs7-data oid\n",
"PKCS7 data");
return NULL;
}
return cryptoctx->id_pkinit_authData9;
case CMS_SIGN_SERVER:
return cryptoctx->id_pkinit_DHKeyData;
case CMS_ENVEL_SERVER:
return cryptoctx->id_pkinit_rkeyData;
default:
return NULL;
}
}
#ifdef LONGHORN_BETA_COMPAT
#if 0
/*
* This is a version that worked with Longhorn Beta 3.
*/
static int
int is_longhorn_server)
{
unsigned char *p = NULL;
pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
/* Get length to wrap the original data with SEQUENCE tag */
if (is_longhorn_server == 0) {
/* Add the signedData OID and adjust lengths */
}
if (p == NULL) return -1;
if (is_longhorn_server == 0) {
i2d_ASN1_OBJECT(oid, &p);
} else {
}
return 0;
}
#else
/*
* This is a version that works with a patched Longhorn KDC.
* (Which should match SP1 ??).
*/
static int
int is_longhorn_server)
{
unsigned char *p = NULL;
pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
/* New longhorn is missing another sequence */
if (is_longhorn_server == 1)
else
/* Get length to wrap the original data with SEQUENCE tag */
/* Always add oid */
if (p == NULL)
return -1;
i2d_ASN1_OBJECT(oid, &p);
/* Wrap in extra seq tag */
if (is_longhorn_server == 1) {
}
return 0;
}
#endif
#else
static int
{
unsigned char *p = NULL;
/* Get length to wrap the original data with SEQUENCE tag */
/* Add the signedData OID and adjust lengths */
if (p == NULL) return -1;
i2d_ASN1_OBJECT(oid, &p);
return 0;
}
#endif
static int
int indata_len,
unsigned char **outdata,
int *outdata_len)
{
/* Solaris Kerberos */
long Tlen;
c.q = *(const unsigned char **)&indata;
c.p= *(const unsigned char **)&indata;
asn1_GetSequence(&c,&length);
c.p += Tlen;
asn1_const_Finish(&c);
/* Solaris Kerberos */
return ENOMEM;
*outdata_len = Tlen;
return 0;
}
#ifndef WITHOUT_PKCS11
static void *
{
void *handle;
/* Solaris Kerberos */
pkiDebug("not found\n");
return NULL;
}
pkiDebug("failed\n");
return NULL;
}
pkiDebug("ok\n");
return handle;
}
static CK_RV
{
/* Solaris Kerberos */
return CKR_GENERAL_ERROR;
return CKR_OK;
}
/*
* Solaris Kerberos: this is a new function that does not exist yet in the MIT
* code.
*
* labelstr will be C string containing token label with trailing white space
* removed.
*/
static void
{
int i;
/*
* \0 terminate labelstr in case the last char in the token label is
* non-whitespace
*/
/* init i so terminating \0 is skipped */
if (labelstr[i] == ' ')
labelstr[i] = '\0';
else
break;
}
}
/*
* Solaris Kerberos: this is a new function that does not exist yet in the MIT
* code.
*/
static krb5_error_code
char *prompt,
int hidden)
{
return (EINVAL);
/*
* Note, assuming this type for now, may need to be passed in in the future.
*/
/* PROMPTER_INVOCATION */
return (r);
}
/*
* Solaris Kerberos: this function was changed to support a PIN being passed
* in. If that is the case the user will not be prompted for their PIN.
*/
static krb5_error_code
{
char *prompt;
int prompt_len;
int r = 0;
return (ENOMEM);
/*
* Don't include NULL string terminator in length calculation as this
* PIN is passed to the C_Login function and only the text chars should
* be considered to be the PIN.
*/
} else {
/* Solaris Kerberos - trim token label */
if (!id_cryptoctx->prompter) {
pkiDebug("pkinit_login: id_cryptoctx->prompter is NULL\n");
/* Solaris Kerberos: Improved error messages */
gettext("Failed to log into token: prompter function is NULL"));
return (KRB5KDC_ERR_PREAUTH_FAILED);
}
/* Solaris Kerberos - Changes for gettext() */
return ENOMEM;
/* Solaris Kerberos - trim token label which can be padded with space */
/* Solaris Kerberos */
/*
* Note that the prompter function will set rdat.length such that the
* NULL terminator is not included
*/
/* PROMPTER_INVOCATION */
}
if (r == 0) {
if (r != CKR_OK) {
/* Solaris Kerberos: Improved error messages */
gettext("Failed to log into token: %s"),
} else {
/* Solaris Kerberos: only need to login once */
}
}
}
return (r);
}
/*
* Solaris Kerberos: added these structs in support of prompting user for
* missing token.
*/
struct _token_entry {
};
struct _token_choices {
unsigned int numtokens;
};
/*
* Solaris Kerberos: this is a new function that does not exist yet in the MIT
* code.
*/
static krb5_error_code
{
"Press enter to continue");
/* note, don't care about the reply */
}
/*
* Solaris Kerberos: new defines for prompting support.
*/
#define CHOOSE_THIS_TOKEN 0
/*
* Solaris Kerberos: this is a new function that does not exist yet in the MIT
* code.
*
* This prompts to user for various choices regarding a token to use. Note
* that if there is no error, choice will be set to one of:
* - the token_choices->token_array entry
* - RESCAN_TOKENS
* - SKIP_TOKENS
*/
static int
struct _token_choices *token_choices,
int *choice)
{
/*
* Assuming that PAM_MAX_MSG_SIZE is a reasonable restriction. Note that -
* 2 is to account for the fact that a krb prompter to PAM conv bridge will
* add ": ".
*/
/* Create the menu prompt */
/* only need to do this once before the for loop */
for (i = 0; i < token_choices->numtokens; i++) {
sizeof (tmplabel));
/* no more smartcards/tokens */
"%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n",
/*
* TRANSLATION_NOTE: Translations of the
* following 5 strings must not exceed 450
* bytes total.
*/
gettext("Select one of the following and press enter:"),
>= sizeof (prompt)) {
pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
gettext("In pkinit_choose_tokens: prompt size"
" %d exceeds prompt buffer size %d"),
gettext("Error: PKINIT prompt message is too large for buffer, "
"please alert the system administrator. Press enter to "
"continue"));
return (r);
return (EINVAL);
}
} else {
"%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n%d: %s\n",
/*
* TRANSLATION_NOTE: Translations of the
* following 6 strings must not exceed 445
* bytes total.
*/
gettext("Select one of the following and press enter:"),
>= sizeof (prompt)) {
pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
gettext("In pkinit_choose_tokens: prompt size"
" %d exceeds prompt buffer size %d"),
gettext("Error: PKINIT prompt message is too large for buffer, "
"please alert the system administrator. Press enter to "
"continue"));
return (r);
return (EINVAL);
}
}
/*
* reply.length needs to be reset to length of tmpbuf before calling
* prompter
*/
return (r);
return (EINVAL);
} else {
/* reply better be digits */
return (EINVAL);
}
errno = 0;
if (errno != 0)
return (errno);
}
switch (tmpchoice) {
case CHOOSE_THIS_TOKEN:
*choice = i; /* chosen entry of token_choices->token_array */
return (0);
case CHOOSE_RESCAN:
return (0);
case CHOOSE_SKIP:
return (0);
case CHOOSE_SEE_NEXT: /* see next smartcard */
continue;
default:
return (EINVAL);
}
}
return (0);
}
/*
* Solaris Kerberos: this is a new function that does not exist yet in the MIT
* code.
*
* Note, this isn't the best solution to providing a function to check the
* certs in a token however I wanted to avoid rewriting a bunch of code so I
* settled for some duplication of processing.
*/
static krb5_error_code
int do_matching,
int load_cert)
{
const unsigned char *cp;
int i, r;
unsigned int nattrs;
nattrs = 2;
if (id_cryptoctx->cert_id_len > 0) {
nattrs++;
}
nattrs++;
}
if (r != CKR_OK) {
gettext("PKCS11 error from C_FindObjectsInit: %s"),
r = EINVAL;
goto out;
}
for (i = 0; ; i++) {
if (i >= MAX_CREDS_ALLOWED) {
r = EINVAL;
goto out;
}
/* Look for x.509 cert */
/* Solaris Kerberos */
break;
}
/* Get cert and id len */
attrs[0].ulValueLen = 0;
obj,
2)) != CKR_OK &&
r != CKR_BUFFER_TOO_SMALL) {
gettext("Error from PKCS11 C_GetAttributeValue: %s"),
r = EINVAL;
goto out;
}
r = ENOMEM;
goto out;
}
r = ENOMEM;
goto out;
}
/* Read the cert and id off the card */
gettext("Error from PKCS11 C_GetAttributeValue: %s"),
r = EINVAL;
goto out;
}
pkiDebug("cert %d size %d id %d idlen %d\n", i,
if (x == NULL) {
r = EINVAL;
goto out;
}
r = ENOMEM;
goto out;
}
}
r = ENOENT;
} else if (do_matching){
/*
* Do not let pkinit_cert_matching set the primary cert in id_cryptoctx
* as this will be done later.
*/
}
out:
if ((r != 0 || !load_cert) &&
/*
* If there's an error or load_cert isn't 1 free all the certs loaded
* onto id_cryptoctx.
*/
}
if (cert)
if (cert_id)
return (r);
}
/*
* Solaris Kerberos: this function has been significantly modified to prompt
* the user in certain cases so defer to this version when resyncing MIT code.
*
* pkinit_open_session now does several things including prompting the user if
* do_matching is set which indicates the code is executing in a client
* context. This function fills out a pkinit_identity_crypto_context with a
* set of certs and a open session if a token can be found that matches all
* supplied criteria. If no token is found then the user is prompted one time
* to insert their token. If there is more than one token that matches all
* client criteria the user is prompted to make a choice if in client context.
* If do_matching is false (KDC context) then the first token matching all
* server criteria is chosen.
*/
static krb5_error_code
int do_matching)
{
int i, r;
int choice = 0;
return 0; /* session already open */
/* Load module */
cctx->p11_module =
return KRB5KDC_ERR_PREAUTH_FAILED;
}
/* Init */
/* Solaris Kerberos: Don't fail if cryptoki is already initialized */
if (r != CKR_OK && r != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
gettext("Error from PKCS11 C_Initialize: %s"),
return KRB5KDC_ERR_PREAUTH_FAILED;
}
/*
* Solaris Kerberos:
* If C_Initialize was already called by the process before the pkinit
* module was loaded then record that fact.
* "finalize_pkcs11" is used by pkinit_fini_pkcs11 to determine whether
* or not C_Finalize() should be called.
*/
/*
* First make sure that is an applicable slot otherwise fail.
*
* Start by getting a count of all slots with or without tokens.
*/
gettext("Error trying to get PKCS11 slot list: %s"),
goto out;
}
if (count == 0) {
/* There are no slots so bail */
gettext("No PKCS11 slots found"));
goto out;
/* See if any of the slots match the specified slotID */
if (tmpslotlist == NULL) {
gettext("Memory allocation error:"));
goto out;
}
gettext("Error trying to get PKCS11 slot list: %s"),
goto out;
}
continue;
if (i >= count) {
/* no slots match */
gettext("Requested PKCS11 slot ID %d not found"),
pkiDebug("open_session: no matching slot found for slotID %d\n",
goto out;
}
}
/* get count of slots that have tokens */
gettext("Error trying to get PKCS11 slot list: %s"),
goto out;
}
if (count == 0) {
/*
* Note, never prompt if !do_matching as this implies KDC side
* processing
*/
/* found slot(s) but no token so prompt and try again */
goto tryagain;
} else {
goto out;
}
} else {
/* already prompted once so bailing */
gettext("No smart card tokens found"));
pkiDebug("pkinit_open_session: no token, already prompted\n");
goto out;
}
}
gettext("Memory allocation error"));
goto out;
}
/*
* Solaris Kerberos: get list of PKCS11 slotid's that have tokens.
*/
gettext("Error trying to get PKCS11 slot list: %s"),
goto out;
}
token_choices.numtokens = 0;
gettext("Memory allocation error"));
goto out;
}
/* examine all the tokens */
for (i = 0; i < count; i++) {
/*
* Solaris Kerberos: if a slotid was specified skip slots that don't
* match.
*/
continue;
/* Open session */
gettext("Error trying to open PKCS11 session: %s"),
goto out;
}
/* Get token info */
gettext("Error trying to read PKCS11 token: %s"),
goto out;
}
/*
* If the token doesn't require login to examine the certs then
* let's check the certs out to see if any match the criteria if
* any.
*/
/*
* It's okay to check the certs if we don't have to login but
* don't load the certs onto cctx at this point, this will be
* done later in this function for the chosen token.
*/
do_matching, 0)) == 0) {
tokenmatch = TRUE;
} else if (r != ENOENT){
goto out;
} else {
/* ignore ENOENT here */
r = 0;
}
} else {
tokenmatch = TRUE;
}
} else {
/* + 1 so tokenlabelstr can be \0 terminated */
/*
* Convert token label into C string with trailing white space
* trimmed.
*/
pkiDebug("open_session: slotid %d token found: \"%s\", "
"cctx->token_label: \"%s\"\n",
/*
* It's okay to check the certs if we don't have to login but
* don't load the certs onto cctx at this point, this will be
* done later in this function for the chosen token.
*/
do_matching, 0)) == 0) {
tokenmatch = TRUE;
} else if (r != ENOENT){
goto out;
} else {
/* ignore ENOENT here */
r = 0;
}
} else {
tokenmatch = TRUE;
}
}
}
if (tokenmatch == TRUE) {
/* add the token to token_choices.token_array */
/* !do_matching implies we take the first matching token */
if (!do_matching)
break;
else
tokenmatch = FALSE;
} else {
}
}
if (token_choices.numtokens == 0) {
/*
* Solaris Kerberos: prompt for token one time if there was no token
* and do_matching is 1 (see earlier comment about do_matching).
*/
goto tryagain;
} else {
goto out;
}
} else {
gettext("No smart card tokens found"));
pkiDebug("open_session: no matching token found\n");
goto out;
}
do_matching) {
pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
goto out;
}
if (choice == RESCAN_TOKENS) {
for (i = 0; i < token_choices.numtokens; i++) {
/* close all sessions */
}
token_choices.numtokens = 0;
goto tryagain;
} else if (choice == SKIP_TOKENS) {
goto out;
} else {
}
} else {
choice = 0; /* really the only choice is the first token_array entry */
}
/* > 1 token so present menu of token choices, let the user decide. */
pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
goto out;
}
if (choice == RESCAN_TOKENS) {
for (i = 0; i < token_choices.numtokens; i++) {
/* close all sessions */
}
token_choices.numtokens = 0;
goto tryagain;
} else if (choice == SKIP_TOKENS) {
goto out;
} else {
}
} else {
goto out;
}
i + 1, (int) count);
/* Login if needed */
/* Solaris Kerberos: added cctx->p11flags check */
}
if (r == 0) {
/* Doing this again to load the certs into cctx. */
}
out:
if (tmpslotlist != NULL)
if (r != 0) {
/* close all sessions if there's an error */
for (i = 0; i < token_choices.numtokens; i++) {
}
} else {
/* close sessions not chosen */
for (i = 0; i < token_choices.numtokens; i++) {
if (i != choice) {
}
}
}
}
return (r);
}
/*
* Look for a key that's:
* 1. private
* 2. capable of the specified operation (usually signing or decrypting)
* 3. RSA (this may be wrong but it's all we can do for now)
* 4. matches the id of the cert we chose
*
* You must call pkinit_get_certs before calling pkinit_find_private_key
* (that's because we need the ID of the private key)
*
* pkcs11 says the id of the key doesn't have to match that of the cert, but
* I can't figure out any other way to decide which key to use.
*
* We should only find one key that fits all the requirements.
* If there are more than one, we just take the first one.
*/
/* ARGSUSED */
{
unsigned int nattrs = 0;
int r;
#ifdef PKINIT_USE_KEY_USAGE
#endif
nattrs++;
#ifdef PKINIT_USE_KEY_USAGE
/*
* Some cards get confused if you try to specify a key usage,
* so don't, and hope for the best. This will fail if you have
* several keys with the same id and different usages but I have
* not seen this on real cards.
*/
true_false = TRUE;
nattrs++;
#endif
nattrs++;
nattrs++;
if (r != CKR_OK) {
pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
return KRB5KDC_ERR_PREAUTH_FAILED;
}
/*
* Solaris Kerberos:
* The CKA_ID may not be correctly set for the private key. For e.g. when
* storing a private key in softtoken pktool(1) doesn't generate or store
* a CKA_ID for the private key. Another way to identify the private key is
* to look for a private key with the same RSA modulus as the public key
* in the certificate.
*/
unsigned int n_len;
unsigned char *n_bytes;
pkiDebug("Failed to extract pub key from cert\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
nattrs = 0;
nattrs++;
#ifdef PKINIT_USE_KEY_USAGE
true_false = TRUE;
nattrs++;
#endif
nattrs++;
return (ENOMEM);
}
pkiDebug("zero-byte key modulus\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
nattrs++;
if (r != CKR_OK) {
pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
return KRB5KDC_ERR_PREAUTH_FAILED;
}
}
return KRB5KDC_ERR_PREAUTH_FAILED;
return 0;
}
#endif
/* ARGSUSED */
static krb5_error_code
unsigned char *data,
unsigned int data_len,
unsigned char **decoded_data,
unsigned int *decoded_data_len)
{
id_cryptoctx->cert_index)) <= 0) {
pkiDebug("failed to decode data\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
return 0;
}
#ifndef WITHOUT_PKCS11
#ifdef SILLYDECRYPT
{
}
return rv;
}
#endif
static krb5_error_code
unsigned char *data,
unsigned int data_len,
unsigned char **decoded_data,
unsigned int *decoded_data_len)
{
unsigned char *cp;
int r;
/*
* Solaris Kerberos: assume session is open and libpkcs11 funcs have been
* loaded.
*/
/* Solaris Kerberos: Login, if needed, to access private object */
if (r != 0)
return r;
if (r != 0)
return r;
}
if (r != 0)
return r;
mech.ulParameterLen = 0;
pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
return KRB5KDC_ERR_PREAUTH_FAILED;
}
return ENOMEM;
#ifdef SILLYDECRYPT
pkiDebug("session %x edata %x edata_len %d data %x datalen @%x %d\n",
#else
#endif
if (r == CKR_BUFFER_TOO_SMALL)
return KRB5KDC_ERR_PREAUTH_FAILED;
}
*decoded_data_len = len;
*decoded_data = cp;
return 0;
}
#endif
unsigned char *data,
unsigned int data_len,
unsigned char **decoded_data,
unsigned int *decoded_data_len)
{
#ifndef WITHOUT_PKCS11
else
#endif
return retval;
}
/* ARGSUSED */
static krb5_error_code
unsigned char *data,
unsigned int data_len,
unsigned char **sig,
unsigned int *sig_len)
{
id_cryptoctx->my_key) != 0) {
pkiDebug("failed to create the signature\n");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
return 0;
}
#ifndef WITHOUT_PKCS11
static krb5_error_code
unsigned char *data,
unsigned int data_len,
unsigned char **sig,
unsigned int *sig_len)
{
unsigned char *cp;
int r;
/*
* Solaris Kerberos: assume session is open and libpkcs11 funcs have been
* loaded.
*/
/* Solaris Kerberos: Login, if needed, to access private object */
if (r != 0)
return r;
if (r != 0)
return r;
}
if (r != 0 )
return r;
mech.ulParameterLen = 0;
return KRB5KDC_ERR_PREAUTH_FAILED;
}
/*
* Key len would give an upper bound on sig size, but there's no way to
* get that. So guess, and if it's too small, re-malloc.
*/
return ENOMEM;
}
if (r != CKR_OK) {
return KRB5KDC_ERR_PREAUTH_FAILED;
}
return 0;
}
#endif
unsigned char *data,
unsigned int data_len,
unsigned char **sig,
unsigned int *sig_len)
{
#ifndef WITHOUT_PKCS11
else
#endif
return retval;
}
static krb5_error_code
{
/* Solaris Kerberos */
int len;
int buf_len = 0;
/* Solaris Kerberos */
return EINVAL;
pkiDebug("private key does not match certificate\n");
/* Solaris Kerberos */
return EINVAL;
}
return ENOMEM;
#if OPENSSL_VERSION_NUMBER < 0x10000000L
#else
#endif
if (len <= 0) {
/* Solaris Kerberos */
return KRB5KRB_ERR_GENERIC;
}
*out_data_len = len;
return 0;
}
static krb5_error_code
{
/* Solaris Kerberos */
return EINVAL;
goto cleanup;
retval = 0;
return retval;
}
/*
* Note:
* This is not the routine the KDC uses to get its certificate.
* This routine is intended to be called by the client
* to obtain the KDC's certificate from some local storage
* to be sent as a hint in its request to the KDC.
*/
/* ARGSUSED */
{
/* Solaris Kerberos */
if (req_cryptoctx == NULL)
return EINVAL;
return 0;
}
/* ARGSUSED */
static krb5_error_code
{
int ret;
/* Solaris Kerberos: Improved error messages */
gettext("Failed to get certificate location"));
goto cleanup;
}
/* Solaris Kerberos: Improved error messages */
gettext("Failed to get private key location"));
goto cleanup;
}
/* Solaris Kerberos: Improved error messages */
gettext("Failed to open PKCS12 file '%s': %s"),
pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
goto cleanup;
}
gettext("Failed to decode PKCS12 file '%s' contents"),
pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
goto cleanup;
}
/*
* Try parsing with no pass phrase first. If that fails,
* prompt for the pass phrase and try again.
*/
if (ret == 0) {
int r = 0;
/* Solaris Kerberos */
pkiDebug("Initial PKCS12_parse with no password failed\n");
/* Solaris Kerberos: use PIN if set */
/* note rdat.length isn't needed in this case */
} else {
if (r >= sizeof(prompt_string)) {
pkiDebug("Prompt string, '%s %s', is too long!\n",
goto cleanup;
}
/* PROMPTER_INVOCATION */
}
if (ret == 0) {
/* Solaris Kerberos: Improved error messages */
gettext("Failed to parse PKCS12 file '%s' with password"),
pkiDebug("Seconde PKCS12_parse with password failed\n");
goto cleanup;
}
}
goto cleanup;
#ifndef WITHOUT_PKCS11
#endif
retval = 0;
if (p12)
if (retval) {
if (x != NULL)
X509_free(x);
if (y != NULL)
EVP_PKEY_free(y);
}
return retval;
}
static krb5_error_code
char *certname,
char *keyname,
int cindex)
{
/* load the certificate */
/* Solaris Kerberos: Improved error messages */
gettext("Failed to load user's certificate from %s: %s"),
goto cleanup;
}
/* Solaris Kerberos: Improved error messages */
gettext("Failed to load user's private key from %s: %s"),
goto cleanup;
}
goto cleanup;
}
#ifndef WITHOUT_PKCS11
#endif
retval = 0;
if (retval) {
if (x != NULL)
X509_free(x);
if (y != NULL)
EVP_PKEY_free(y);
}
return retval;
}
/* ARGSUSED */
static krb5_error_code
{
goto cleanup;
}
pkiDebug("%s: failed to get user's private key location\n",
goto cleanup;
}
idopts->key_filename, 0);
return retval;
}
/* ARGSUSED */
static krb5_error_code
{
/* Solaris Kerberos */
int i = 0, len;
/* Solaris Kerberos */
return EINVAL;
pkiDebug("%s: failed to get user's certificate directory location\n",
return ENOENT;
}
if (d == NULL) {
/* Solaris Kerberos: Improved error messages */
gettext("Failed to open directory \"%s\": %s"),
return errno;
}
/*
* We'll assume that certs are named XXX.crt and the corresponding
* key is named XXX.key
*/
/* Ignore subdirectories and anything starting with a dot */
#ifdef DT_DIR
continue;
#endif
continue;
if (len < 5)
continue;
continue;
/* Checked length */
pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
continue;
}
if (retval == 0) {
pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
i++;
}
else
continue;
}
if (i == 0) {
/* Solaris Kerberos: Improved error messages */
goto cleanup;
}
retval = 0;
if (d)
(void) closedir(d);
return retval;
}
#ifndef WITHOUT_PKCS11
/* ARGSUSED */
static krb5_error_code
int do_matching)
{
#ifdef PKINIT_USE_MECH_LIST
#endif
return KRB5KDC_ERR_PREAUTH_FAILED;
/* Copy stuff from idopts -> id_cryptoctx */
return ENOMEM;
}
return ENOMEM;
}
return ENOMEM;
}
return ENOMEM;
}
/* Convert the ascii cert_id string into a binary blob */
/*
* Solaris Kerberos:
* If the cert_id_string is empty then behave in a similar way to how
* an empty certlabel is treated - i.e. don't fail now but rather continue
* as though the certid wasn't specified.
*/
return ENOMEM;
return ENOMEM;
}
}
#ifndef PKINIT_USE_MECH_LIST
/*
* We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
* many cards seems to be confused about whether they are capable of
* this or not. The safe thing seems to be to ignore the mechanism list,
* always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
*/
#else
return KRB5KDC_ERR_PREAUTH_FAILED;
}
return ENOMEM;
return KRB5KDC_ERR_PREAUTH_FAILED;
}
for (i = 0; i < count; i++) {
return KRB5KDC_ERR_PREAUTH_FAILED;
}
#ifdef DEBUG_MECHINFO
pkiDebug(" this mech is good for sign & decrypt\n");
#endif
if (mechp[i] == CKM_RSA_PKCS) {
/* This seems backwards... */
id_cryptoctx->mech =
}
}
#endif
}
#endif
/* ARGSUSED */
static void
struct _pkinit_cred_info *cred)
{
#ifndef WITHOUT_PKCS11
#endif
}
}
/* ARGSUSED */
{
int i;
if (id_cryptoctx == NULL)
return EINVAL;
for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
}
}
return 0;
}
int do_matching)
{
case IDTYPE_FILE:
break;
case IDTYPE_DIR:
break;
#ifndef WITHOUT_PKCS11
case IDTYPE_PKCS11:
break;
#endif
case IDTYPE_PKCS12:
break;
default:
}
/* Solaris Kerberos */
return retval;
}
/*
* Get number of certificates available after crypto_load_certs()
*/
/* ARGSUSED */
int *cert_count)
{
int count;
return EINVAL;
for (count = 0;
count++);
*cert_count = count;
return 0;
}
/*
* Begin iteration over the certs loaded in crypto_load_certs()
*/
/* ARGSUSED */
{
return EINVAL;
return ENOENT;
return ENOMEM;
return 0;
}
/*
* End iteration over the certs loaded in crypto_load_certs()
*/
/* ARGSUSED */
{
return EINVAL;
return 0;
}
/*
* Get next certificate handle
*/
/* ARGSUSED */
{
return EINVAL;
return EINVAL;
if (id_cryptoctx == NULL)
return EINVAL;
return PKINIT_ITER_NO_MORE;
return ENOMEM;
return 0;
}
/*
* Release cert handle
*/
/* ARGSUSED */
{
return EINVAL;
return 0;
}
/*
* Get certificate Key Usage and Extended Key Usage
*/
/* ARGSUSED */
static krb5_error_code
X509 *x,
unsigned int *ret_ku_bits,
unsigned int *ret_eku_bits)
{
/* Solaris Kerberos */
int i;
return EINVAL;
if (ret_eku_bits)
*ret_eku_bits = 0;
else {
goto check_kus;
}
/* Start with Extended Key usage */
if (i >= 0) {
if (eku) {
for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
}
}
}
*ret_eku_bits = eku_bits;
/* Now the Key Usage bits */
if (ret_ku_bits)
*ret_ku_bits = 0;
else {
goto out;
}
/* Make sure usage exists before checking bits */
if (usage) {
if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
}
*ret_ku_bits = ku_bits;
out:
return 0;
}
/*
* Return a string format of an X509_NAME in buf where
* of the buffer, and on output it is the actual length
* of the name.
* If buf is NULL, returns the length req'd to hold name
*/
static char *
char *buf,
unsigned int *size,
unsigned long flag)
{
}
else {
}
}
return (buf);
}
/*
* Get certificate information
*/
{
int i, j;
return EINVAL;
return EINVAL;
return ENOMEM;
/* get the subject name (in rfc2253 format) */
goto cleanup;
}
/* get the issuer name (in rfc2253 format) */
goto cleanup;
}
/* get the san data */
if (retval)
goto cleanup;
j = 0;
if (pkinit_sans != NULL) {
for (i = 0; pkinit_sans[i] != NULL; i++)
j++;
}
j++;
}
if (j != 0) {
goto cleanup;
}
j = 0;
if (pkinit_sans != NULL) {
for (i = 0; pkinit_sans[i] != NULL; i++)
}
}
} else
/* get the KU and EKU data */
if (retval)
goto cleanup;
retval = 0;
if (retval) {
if (md)
}
return retval;
}
/*
* Free certificate information
*/
{
int i;
return EINVAL;
if (md->subject_dn)
}
return 0;
}
/*
* Make this matching certificate "the chosen one"
*/
/* ARGSUSED */
{
return EINVAL;
return EINVAL;
/* copy the selected cert into our id_cryptoctx */
}
}
#ifndef WITHOUT_PKCS11
else {
}
#endif
return 0;
}
/*
* Choose the default certificate as "the chosen one"
*/
{
int cert_count = 0;
if (retval) {
pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
goto errout;
}
if (cert_count != 1) {
/* Solaris Kerberos: Improved error messages */
gettext("Failed to select default certificate: "
"found %d certs to choose from but there must be exactly one"),
pkiDebug("%s: ERROR: There are %d certs to choose from, "
"but there must be exactly one.\n",
goto errout;
}
/* copy the selected cert into our id_cryptoctx */
}
id_cryptoctx->cert_index = 0;
}
#ifndef WITHOUT_PKCS11
else {
}
#endif
retval = 0;
return retval;
}
/* ARGSUSED */
static krb5_error_code
int catype,
char *filename)
{
/* Solaris Kerberos */
int i = 0;
/* If there isn't already a stack in the context,
* create a temporary one now */
switch(catype) {
case CATYPE_ANCHORS:
else {
ca_certs = sk_X509_new_null();
return ENOMEM;
}
break;
case CATYPE_INTERMEDIATES:
else {
ca_certs = sk_X509_new_null();
return ENOMEM;
}
break;
case CATYPE_CRLS:
else {
return ENOMEM;
}
break;
default:
return ENOTSUP;
}
goto cleanup;
}
goto cleanup;
}
/* scan over the stack created from loading the file contents,
* weed out duplicates, and push new ones onto the return stack
*/
for (i = 0; i < sk_X509_INFO_num(sk); i++) {
if (!size) {
continue;
}
for (j = 0; j < size; j++) {
if (flag == 0)
break;
else
continue;
}
if (flag != 0) {
}
if (!size) {
continue;
}
for (j = 0; j < size; j++) {
if (flag == 0)
break;
else
continue;
}
if (flag != 0) {
}
}
}
/* If we added something and there wasn't a stack in the
* context before, add the temporary stack to the context.
*/
switch(catype) {
case CATYPE_ANCHORS:
if (sk_X509_num(ca_certs) == 0) {
} else {
}
break;
case CATYPE_INTERMEDIATES:
if (sk_X509_num(ca_certs) == 0) {
} else {
}
break;
case CATYPE_CRLS:
if (sk_X509_CRL_num(ca_crls) == 0) {
} else {
}
break;
default:
/* Should have been caught above! */
goto cleanup;
/* Solaris Kerberos: removed "break" as it's never reached */
}
retval = 0;
return retval;
}
static krb5_error_code
int catype,
char *dirname)
{
return EINVAL;
if (d == NULL)
return ENOENT;
pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
goto cleanup;
}
/* Ignore subdirectories and anything starting with a dot */
#ifdef DT_DIR
continue;
#endif
continue;
if (retval)
goto cleanup;
}
retval = 0;
if (d != NULL)
(void) closedir(d);
return retval;
}
/* ARGSUSED */
int idtype,
int catype,
char *id)
{
pkiDebug("%s: called with idtype %s and catype %s\n",
/* Solaris Kerberos: Removed "break"'s as they are never reached */
switch (idtype) {
case IDTYPE_FILE:
case IDTYPE_DIR:
default:
return ENOTSUP;
}
}
static krb5_error_code
{
unsigned char *p = NULL;
int len = 0;
krb5_cas =
return ENOMEM;
for (i = 0; i < sk_size; i++) {
krb5_cas[i] = (krb5_external_principal_identifier *)malloc(sizeof(krb5_external_principal_identifier));
x = sk_X509_value(sk, i);
/* fill-in subjectName */
xn = X509_get_subject_name(x);
goto cleanup;
i2d_X509_NAME(xn, &p);
/* fill-in issuerAndSerialNumber */
#ifdef LONGHORN_BETA_COMPAT
if (longhorn == 0) { /* XXX Longhorn doesn't like this */
#endif
goto cleanup;
#ifdef LONGHORN_BETA_COMPAT
}
#endif
/* fill-in subjectKeyIdentifier */
#ifdef LONGHORN_BETA_COMPAT
if (longhorn == 0) { /* XXX Longhorn doesn't like this */
#endif
NULL))) {
goto cleanup;
i2d_ASN1_OCTET_STRING(ikeyid, &p);
}
}
#ifdef LONGHORN_BETA_COMPAT
}
#endif
}
}
retval = 0;
if (retval)
return retval;
}
/* ARGSUSED */
static krb5_error_code
{
return KRB5KDC_ERR_PREAUTH_FAILED;
sk = sk_X509_new_null();
goto cleanup;
return retval;
}
/* ARGSUSED */
{
goto cleanup;
goto cleanup;
}
if (retval) {
goto cleanup;
}
retval = 0;
return retval;
}
/* ARGSUSED */
{
/* Solaris Kerberos */
return KRB5KDC_ERR_PREAUTH_FAILED;
}
/* ARGSUSED */
int flag,
krb5_trusted_ca *** ids)
{
unsigned char *p = NULL;
return KRB5KDC_ERR_PREAUTH_FAILED;
return ENOMEM;
for (i = 0; i < sk_size; i++) {
goto cleanup;
x = sk_X509_value(sk, i);
switch (flag) {
break;
xn = X509_get_subject_name(x);
goto cleanup;
i2d_X509_NAME(xn, &p);
break;
goto cleanup;
}
break;
default: break;
}
}
retval = 0;
if (retval)
return retval;
}
/* ARGSUSED */
unsigned char **out,
unsigned int *out_len)
{
unsigned char *p = NULL;
int len = 0;
*out_len = 0;
return 0;
goto cleanup;
retval = 0;
return retval;
}
static int
{
/* Solaris Kerberos */
int i = 0;
return 0;
if(!PKCS7_type_is_enveloped(p7)) {
pkiDebug("wrong pkcs7 content type\n");
return 0;
}
pkiDebug("unable to decrypt pkcs7 object\n");
return 0;
}
/* Solaris Kerberos: Suppress sun studio compiler warning */
for(;;) {
if (i <= 0) break;
return 1;
}
#pragma error_messages (default, E_END_OF_LOOP_CODE_NOT_REACHED)
return 0;
}
int td_type)
{
const unsigned char *p = NULL;
int i = 0;
if (td_type == TD_TRUSTED_CERTIFIERS)
pkiDebug("received trusted certifiers\n");
else
pkiDebug("received invalid certificate\n");
while(krb5_trusted_certifiers[i] != NULL) {
goto cleanup;
if (td_type == TD_TRUSTED_CERTIFIERS)
else
}
goto cleanup;
if (td_type == TD_TRUSTED_CERTIFIERS)
pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
else
}
goto cleanup;
/* XXX */
}
i++;
}
/* XXX Since we not doing anything with received trusted certifiers
* return an error. this is the place where we can pick a different
* client certificate based on the information in td_trusted_certifiers
*/
return retval;
}
static BIO *
{
int i = 0;
/* Solaris Kerberos: Not used */
#if 0
#endif
if (evp_cipher == NULL) {
goto cleanup;
}
/* Solaris Kerberos: Not used */
#if 0
#endif
goto cleanup;
}
/* It was encrypted, we need to decrypt the secret key
* with the private key */
/* Find the recipientInfo which matches the passed certificate
* (if any)
*/
if (cert) {
for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
int tmp_ret = 0;
if (!tmp_ret) {
if (!tmp_ret)
break;
}
}
goto cleanup;
}
}
/* If we haven't got a certificate try each ri in turn */
for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
if (jj) {
goto cleanup;
}
break;
}
}
goto cleanup;
}
}
else {
/* Solaris Kerberos: tmp_len is unsigned. Cannot be < 0 */
goto cleanup;
}
}
goto cleanup;
goto cleanup;
* and effective key length. The key length is
* determined by the size of the decrypted RSA key.
*/
goto cleanup;
}
}
goto cleanup;
else
else {
}
/* Solaris Kerberos */
goto out;
out:
return(out);
}
static krb5_error_code
{
/* Solaris Kerberos */
ASN1_OCTET_STRING *s = NULL;
const unsigned char *p = data;
goto cleanup;
goto cleanup;
}
retval = 0;
if (s != NULL)
return retval;
}
#ifdef DEBUG_DH
static void
{
if (msg)
if (dh)
}
static void
{
if (msg)
if (key)
}
#endif
/*
* Solaris Kerberos:
* Error message generation has changed so gettext() can be used
*/
#if 0
static char *
{
int i;
static char uc[64];
break;
return (pkcs11_errstrings[i].text);
return (uc);
}
#endif
static char *
return pkcs11_error_table(err);
}