2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A/*
2N/A * COPYRIGHT (C) 2006,2007
2N/A * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
2N/A * ALL RIGHTS RESERVED
2N/A *
2N/A * Permission is granted to use, copy, create derivative works
2N/A * and redistribute this software and such derivative works
2N/A * for any purpose, so long as the name of The University of
2N/A * Michigan is not used in any advertising or publicity
2N/A * pertaining to the use of distribution of this software
2N/A * without specific, written prior authorization. If the
2N/A * above copyright notice or any other identification of the
2N/A * University of Michigan is included in any copy of any
2N/A * portion of this software, then the disclaimer below must
2N/A * also be included.
2N/A *
2N/A * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
2N/A * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
2N/A * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
2N/A * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
2N/A * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
2N/A * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
2N/A * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
2N/A * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
2N/A * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
2N/A * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
2N/A * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
2N/A * SUCH DAMAGES.
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <errno.h>
2N/A#include <string.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <dlfcn.h>
2N/A#include <unistd.h>
2N/A#include <dirent.h>
2N/A
2N/A
2N/A/* Solaris Kerberos */
2N/A#include <libintl.h>
2N/A#include <assert.h>
2N/A#include <security/pam_appl.h>
2N/A#include <ctype.h>
2N/A#include "k5-int.h"
2N/A#include <ctype.h>
2N/A
2N/A/*
2N/A * Q: What is this SILLYDECRYPT stuff about?
2N/A * A: When using the ActivCard Linux pkcs11 library (v2.0.1),
2N/A * the decrypt function fails. By inserting an extra
2N/A * function call, which serves nothing but to change the
2N/A * stack, we were able to work around the issue. If the
2N/A * ActivCard library is fixed in the future, this
2N/A * definition and related code can be removed.
2N/A */
2N/A#define SILLYDECRYPT
2N/A
2N/A#include "pkinit_crypto_openssl.h"
2N/A
2N/A#if OPENSSL_VERSION_NUMBER >= 0x10000000L
2N/A/* Use CMS support present in OpenSSL 1.0 and later. */
2N/A#include <openssl/cms.h>
2N/A#define pkinit_CMS_free1_crls(_sk_x509crl) sk_X509_CRL_free((_sk_x509crl))
2N/A#define pkinit_CMS_free1_certs(_sk_x509) sk_X509_free((_sk_x509))
2N/A#define pkinit_CMS_SignerInfo_get_cert(_cms,_si,_x509_pp) \
2N/A CMS_SignerInfo_get0_algs(_si,NULL,_x509_pp,NULL,NULL)
2N/A#else
2N/A/* Fake up CMS support using PKCS7. */
2N/A#define pkinit_CMS_free1_crls(_stack_of_x509crls) /* Don't free these */
2N/A#define pkinit_CMS_free1_certs(_stack_of_x509certs) /* Don't free these */
2N/A#define CMS_NO_SIGNER_CERT_VERIFY PKCS7_NOVERIFY
2N/A#define CMS_NOATTR PKCS7_NOATTR
2N/A#define CMS_ContentInfo PKCS7
2N/A#define CMS_SignerInfo PKCS7_SIGNER_INFO
2N/A#define d2i_CMS_ContentInfo d2i_PKCS7
2N/A#define CMS_get0_type(_p7) ((_p7)->type)
2N/A#define CMS_get0_content(_p7) (&((_p7)->d.other->value.octet_string))
2N/A#define CMS_set1_signers_certs(_p7,_stack_of_x509,_uint)
2N/A#define CMS_get0_SignerInfos PKCS7_get_signer_info
2N/A#define stack_st_CMS_SignerInfo stack_st_PKCS7_SIGNER_INFO
2N/A#undef sk_CMS_SignerInfo_value
2N/A#define sk_CMS_SignerInfo_value sk_PKCS7_SIGNER_INFO_value
2N/A#define CMS_get0_eContentType(_p7) (_p7->d.sign->contents->type)
2N/A#define CMS_verify PKCS7_verify
2N/A#define CMS_get1_crls(_p7) (_p7->d.sign->crl)
2N/A#define CMS_get1_certs(_p7) (_p7->d.sign->cert)
2N/A#define CMS_ContentInfo_free(_p7) PKCS7_free(_p7)
2N/A#define pkinit_CMS_SignerInfo_get_cert(_p7,_si,_x509_pp) \
2N/A (*_x509_pp) = PKCS7_cert_from_signer_info(_p7,_si)
2N/A#endif
2N/A
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * Changed to a switch statement so gettext() can be used
2N/A * for internationization.
2N/A * Use defined constants rather than raw numbers for error codes.
2N/A */
2N/Astatic char *
2N/Apkcs11_error_table(short code) {
2N/A switch (code) {
2N/A case CKR_OK:
2N/A return (gettext("ok"));
2N/A case CKR_CANCEL:
2N/A return (gettext("cancel"));
2N/A case CKR_HOST_MEMORY:
2N/A return (gettext("host memory"));
2N/A case CKR_SLOT_ID_INVALID:
2N/A return (gettext("slot id invalid"));
2N/A case CKR_GENERAL_ERROR:
2N/A return (gettext("general error"));
2N/A case CKR_FUNCTION_FAILED:
2N/A return (gettext("function failed"));
2N/A case CKR_ARGUMENTS_BAD:
2N/A return (gettext("arguments bad"));
2N/A case CKR_NO_EVENT:
2N/A return (gettext("no event"));
2N/A case CKR_NEED_TO_CREATE_THREADS:
2N/A return (gettext("need to create threads"));
2N/A case CKR_CANT_LOCK:
2N/A return (gettext("cant lock"));
2N/A case CKR_ATTRIBUTE_READ_ONLY:
2N/A return (gettext("attribute read only"));
2N/A case CKR_ATTRIBUTE_SENSITIVE:
2N/A return (gettext("attribute sensitive"));
2N/A case CKR_ATTRIBUTE_TYPE_INVALID:
2N/A return (gettext("attribute type invalid"));
2N/A case CKR_ATTRIBUTE_VALUE_INVALID:
2N/A return (gettext("attribute value invalid"));
2N/A case CKR_DATA_INVALID:
2N/A return (gettext("data invalid"));
2N/A case CKR_DATA_LEN_RANGE:
2N/A return (gettext("data len range"));
2N/A case CKR_DEVICE_ERROR:
2N/A return (gettext("device error"));
2N/A case CKR_DEVICE_MEMORY:
2N/A return (gettext("device memory"));
2N/A case CKR_DEVICE_REMOVED:
2N/A return (gettext("device removed"));
2N/A case CKR_ENCRYPTED_DATA_INVALID:
2N/A return (gettext("encrypted data invalid"));
2N/A case CKR_ENCRYPTED_DATA_LEN_RANGE:
2N/A return (gettext("encrypted data len range"));
2N/A case CKR_FUNCTION_CANCELED:
2N/A return (gettext("function canceled"));
2N/A case CKR_FUNCTION_NOT_PARALLEL:
2N/A return (gettext("function not parallel"));
2N/A case CKR_FUNCTION_NOT_SUPPORTED:
2N/A return (gettext("function not supported"));
2N/A case CKR_KEY_HANDLE_INVALID:
2N/A return (gettext("key handle invalid"));
2N/A case CKR_KEY_SIZE_RANGE:
2N/A return (gettext("key size range"));
2N/A case CKR_KEY_TYPE_INCONSISTENT:
2N/A return (gettext("key type inconsistent"));
2N/A case CKR_KEY_NOT_NEEDED:
2N/A return (gettext("key not needed"));
2N/A case CKR_KEY_CHANGED:
2N/A return (gettext("key changed"));
2N/A case CKR_KEY_NEEDED:
2N/A return (gettext("key needed"));
2N/A case CKR_KEY_INDIGESTIBLE:
2N/A return (gettext("key indigestible"));
2N/A case CKR_KEY_FUNCTION_NOT_PERMITTED:
2N/A return (gettext("key function not permitted"));
2N/A case CKR_KEY_NOT_WRAPPABLE:
2N/A return (gettext("key not wrappable"));
2N/A case CKR_KEY_UNEXTRACTABLE:
2N/A return (gettext("key unextractable"));
2N/A case CKR_MECHANISM_INVALID:
2N/A return (gettext("mechanism invalid"));
2N/A case CKR_MECHANISM_PARAM_INVALID:
2N/A return (gettext("mechanism param invalid"));
2N/A case CKR_OBJECT_HANDLE_INVALID:
2N/A return (gettext("object handle invalid"));
2N/A case CKR_OPERATION_ACTIVE:
2N/A return (gettext("operation active"));
2N/A case CKR_OPERATION_NOT_INITIALIZED:
2N/A return (gettext("operation not initialized"));
2N/A case CKR_PIN_INCORRECT:
2N/A return (gettext("pin incorrect"));
2N/A case CKR_PIN_INVALID:
2N/A return (gettext("pin invalid"));
2N/A case CKR_PIN_LEN_RANGE:
2N/A return (gettext("pin len range"));
2N/A case CKR_PIN_EXPIRED:
2N/A return (gettext("pin expired"));
2N/A case CKR_PIN_LOCKED:
2N/A return (gettext("pin locked"));
2N/A case CKR_SESSION_CLOSED:
2N/A return (gettext("session closed"));
2N/A case CKR_SESSION_COUNT:
2N/A return (gettext("session count"));
2N/A case CKR_SESSION_HANDLE_INVALID:
2N/A return (gettext("session handle invalid"));
2N/A case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
2N/A return (gettext("session parallel not supported"));
2N/A case CKR_SESSION_READ_ONLY:
2N/A return (gettext("session read only"));
2N/A case CKR_SESSION_EXISTS:
2N/A return (gettext("session exists"));
2N/A case CKR_SESSION_READ_ONLY_EXISTS:
2N/A return (gettext("session read only exists"));
2N/A case CKR_SESSION_READ_WRITE_SO_EXISTS:
2N/A return (gettext("session read write so exists"));
2N/A case CKR_SIGNATURE_INVALID:
2N/A return (gettext("signature invalid"));
2N/A case CKR_SIGNATURE_LEN_RANGE:
2N/A return (gettext("signature len range"));
2N/A case CKR_TEMPLATE_INCOMPLETE:
2N/A return (gettext("template incomplete"));
2N/A case CKR_TEMPLATE_INCONSISTENT:
2N/A return (gettext("template inconsistent"));
2N/A case CKR_TOKEN_NOT_PRESENT:
2N/A return (gettext("token not present"));
2N/A case CKR_TOKEN_NOT_RECOGNIZED:
2N/A return (gettext("token not recognized"));
2N/A case CKR_TOKEN_WRITE_PROTECTED:
2N/A return (gettext("token write protected"));
2N/A case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
2N/A return (gettext("unwrapping key handle invalid"));
2N/A case CKR_UNWRAPPING_KEY_SIZE_RANGE:
2N/A return (gettext("unwrapping key size range"));
2N/A case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
2N/A return (gettext("unwrapping key type inconsistent"));
2N/A case CKR_USER_ALREADY_LOGGED_IN:
2N/A return (gettext("user already logged in"));
2N/A case CKR_USER_NOT_LOGGED_IN:
2N/A return (gettext("user not logged in"));
2N/A case CKR_USER_PIN_NOT_INITIALIZED:
2N/A return (gettext("user pin not initialized"));
2N/A case CKR_USER_TYPE_INVALID:
2N/A return (gettext("user type invalid"));
2N/A case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
2N/A return (gettext("user another already logged in"));
2N/A case CKR_USER_TOO_MANY_TYPES:
2N/A return (gettext("user too many types"));
2N/A case CKR_WRAPPED_KEY_INVALID:
2N/A return (gettext("wrapped key invalid"));
2N/A case CKR_WRAPPED_KEY_LEN_RANGE:
2N/A return (gettext("wrapped key len range"));
2N/A case CKR_WRAPPING_KEY_HANDLE_INVALID:
2N/A return (gettext("wrapping key handle invalid"));
2N/A case CKR_WRAPPING_KEY_SIZE_RANGE:
2N/A return (gettext("wrapping key size range"));
2N/A case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
2N/A return (gettext("wrapping key type inconsistent"));
2N/A case CKR_RANDOM_SEED_NOT_SUPPORTED:
2N/A return (gettext("random seed not supported"));
2N/A case CKR_RANDOM_NO_RNG:
2N/A return (gettext("random no rng"));
2N/A case CKR_DOMAIN_PARAMS_INVALID:
2N/A return (gettext("domain params invalid"));
2N/A case CKR_BUFFER_TOO_SMALL:
2N/A return (gettext("buffer too small"));
2N/A case CKR_SAVED_STATE_INVALID:
2N/A return (gettext("saved state invalid"));
2N/A case CKR_INFORMATION_SENSITIVE:
2N/A return (gettext("information sensitive"));
2N/A case CKR_STATE_UNSAVEABLE:
2N/A return (gettext("state unsaveable"));
2N/A case CKR_CRYPTOKI_NOT_INITIALIZED:
2N/A return (gettext("cryptoki not initialized"));
2N/A case CKR_CRYPTOKI_ALREADY_INITIALIZED:
2N/A return (gettext("cryptoki already initialized"));
2N/A case CKR_MUTEX_BAD:
2N/A return (gettext("mutex bad"));
2N/A case CKR_MUTEX_NOT_LOCKED:
2N/A return (gettext("mutex not locked"));
2N/A case CKR_FUNCTION_REJECTED:
2N/A return (gettext("function rejected"));
2N/A default:
2N/A return (gettext("unknown error"));
2N/A }
2N/A}
2N/A
2N/A/* DH parameters */
2N/Aunsigned char pkinit_1024_dhprime[128] = {
2N/A 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2N/A 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
2N/A 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
2N/A 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
2N/A 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
2N/A 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
2N/A 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
2N/A 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
2N/A 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
2N/A 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
2N/A 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
2N/A 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
2N/A 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
2N/A 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
2N/A 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
2N/A 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
2N/A};
2N/A
2N/Aunsigned char pkinit_2048_dhprime[2048/8] = {
2N/A 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2N/A 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
2N/A 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
2N/A 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
2N/A 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
2N/A 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
2N/A 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
2N/A 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
2N/A 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
2N/A 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
2N/A 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
2N/A 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
2N/A 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
2N/A 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
2N/A 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
2N/A 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
2N/A 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
2N/A 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
2N/A 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
2N/A 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
2N/A 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
2N/A 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
2N/A 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
2N/A 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
2N/A 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
2N/A 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
2N/A 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
2N/A 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
2N/A 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
2N/A 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
2N/A 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
2N/A 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
2N/A};
2N/A
2N/Aunsigned char pkinit_4096_dhprime[4096/8] = {
2N/A 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2N/A 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
2N/A 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
2N/A 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
2N/A 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
2N/A 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
2N/A 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
2N/A 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
2N/A 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
2N/A 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
2N/A 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
2N/A 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
2N/A 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
2N/A 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
2N/A 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
2N/A 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
2N/A 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
2N/A 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
2N/A 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
2N/A 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
2N/A 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
2N/A 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
2N/A 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
2N/A 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
2N/A 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
2N/A 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
2N/A 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
2N/A 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
2N/A 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
2N/A 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
2N/A 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
2N/A 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
2N/A 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
2N/A 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
2N/A 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
2N/A 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
2N/A 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
2N/A 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
2N/A 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
2N/A 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
2N/A 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
2N/A 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
2N/A 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
2N/A 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
2N/A 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
2N/A 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
2N/A 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
2N/A 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
2N/A 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
2N/A 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
2N/A 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
2N/A 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
2N/A 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
2N/A 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
2N/A 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
2N/A 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
2N/A 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
2N/A 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
2N/A 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
2N/A 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
2N/A 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
2N/A 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
2N/A 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
2N/A 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
2N/A};
2N/A
2N/A/* Solaris Kerberos */
2N/Astatic k5_mutex_t oids_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
2N/Astatic int pkinit_oids_refs = 0;
2N/A
2N/Akrb5_error_code
2N/Apkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) {
2N/A
2N/A krb5_error_code retval = ENOMEM;
2N/A pkinit_plg_crypto_context ctx = NULL;
2N/A
2N/A /* initialize openssl routines */
2N/A /* Solaris Kerberos */
2N/A retval = openssl_init();
2N/A if (retval != 0)
2N/A goto out;
2N/A
2N/A ctx = (pkinit_plg_crypto_context)malloc(sizeof(*ctx));
2N/A if (ctx == NULL)
2N/A goto out;
2N/A (void) memset(ctx, 0, sizeof(*ctx));
2N/A
2N/A pkiDebug("%s: initializing openssl crypto context at %p\n",
2N/A __FUNCTION__, ctx);
2N/A retval = pkinit_init_pkinit_oids(ctx);
2N/A if (retval)
2N/A goto out;
2N/A
2N/A retval = pkinit_init_dh_params(ctx);
2N/A if (retval)
2N/A goto out;
2N/A
2N/A *cryptoctx = ctx;
2N/A
2N/Aout:
2N/A if (retval && ctx != NULL)
2N/A pkinit_fini_plg_crypto(ctx);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Avoid
2N/Apkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)
2N/A{
2N/A pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx);
2N/A
2N/A if (cryptoctx == NULL)
2N/A return;
2N/A pkinit_fini_pkinit_oids(cryptoctx);
2N/A pkinit_fini_dh_params(cryptoctx);
2N/A free(cryptoctx);
2N/A}
2N/A
2N/Akrb5_error_code
2N/Apkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
2N/A{
2N/A krb5_error_code retval = ENOMEM;
2N/A pkinit_identity_crypto_context ctx = NULL;
2N/A
2N/A ctx = (pkinit_identity_crypto_context)malloc(sizeof(*ctx));
2N/A if (ctx == NULL)
2N/A goto out;
2N/A (void) memset(ctx, 0, sizeof(*ctx));
2N/A
2N/A retval = pkinit_init_certs(ctx);
2N/A if (retval)
2N/A goto out;
2N/A
2N/A retval = pkinit_init_pkcs11(ctx);
2N/A if (retval)
2N/A goto out;
2N/A
2N/A pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
2N/A *idctx = ctx;
2N/A
2N/Aout:
2N/A if (retval) {
2N/A if (ctx)
2N/A pkinit_fini_identity_crypto(ctx);
2N/A }
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Avoid
2N/Apkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
2N/A{
2N/A if (idctx == NULL)
2N/A return;
2N/A
2N/A pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, idctx);
2N/A pkinit_fini_certs(idctx);
2N/A pkinit_fini_pkcs11(idctx);
2N/A free(idctx);
2N/A}
2N/A
2N/Akrb5_error_code
2N/Apkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
2N/A{
2N/A
2N/A pkinit_req_crypto_context ctx = NULL;
2N/A
2N/A /* Solaris Kerberos */
2N/A if (cryptoctx == NULL)
2N/A return EINVAL;
2N/A
2N/A ctx = (pkinit_req_crypto_context)malloc(sizeof(*ctx));
2N/A if (ctx == NULL)
2N/A return ENOMEM;
2N/A (void) memset(ctx, 0, sizeof(*ctx));
2N/A
2N/A ctx->dh = NULL;
2N/A ctx->received_cert = NULL;
2N/A
2N/A *cryptoctx = ctx;
2N/A
2N/A pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
2N/A
2N/A return 0;
2N/A}
2N/A
2N/Avoid
2N/Apkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
2N/A{
2N/A if (req_cryptoctx == NULL)
2N/A return;
2N/A
2N/A pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, req_cryptoctx);
2N/A if (req_cryptoctx->dh != NULL)
2N/A DH_free(req_cryptoctx->dh);
2N/A if (req_cryptoctx->received_cert != NULL)
2N/A X509_free(req_cryptoctx->received_cert);
2N/A
2N/A free(req_cryptoctx);
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Apkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
2N/A{
2N/A krb5_error_code retval = ENOMEM;
2N/A int nid = 0;
2N/A
2N/A /*
2N/A * If OpenSSL already knows about the OID, use the
2N/A * existing definition. Otherwise, create an OID object.
2N/A */
2N/A #define CREATE_OBJ_IF_NEEDED(oid, vn, sn, ln) \
2N/A nid = OBJ_txt2nid(oid); \
2N/A if (nid == NID_undef) { \
2N/A nid = OBJ_create(oid, sn, ln); \
2N/A if (nid == NID_undef) { \
2N/A pkiDebug("Error creating oid object for '%s'\n", oid); \
2N/A goto out; \
2N/A } \
2N/A } \
2N/A ctx->vn = OBJ_nid2obj(nid);
2N/A
2N/A /* Solaris Kerberos */
2N/A retval = k5_mutex_lock(&oids_mutex);
2N/A if (retval != 0)
2N/A goto out;
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.2", id_pkinit_san,
2N/A "id-pkinit-san", "KRB5PrincipalName");
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.1", id_pkinit_authData,
2N/A "id-pkinit-authdata", "PKINIT signedAuthPack");
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.2", id_pkinit_DHKeyData,
2N/A "id-pkinit-DHKeyData", "PKINIT dhSignedData");
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.3", id_pkinit_rkeyData,
2N/A "id-pkinit-rkeyData", "PKINIT encKeyPack");
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.4", id_pkinit_KPClientAuth,
2N/A "id-pkinit-KPClientAuth", "PKINIT Client EKU");
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.5", id_pkinit_KPKdc,
2N/A "id-pkinit-KPKdc", "KDC EKU");
2N/A
2N/A#if 0
2N/A CREATE_OBJ_IF_NEEDED("1.2.840.113549.1.7.1", id_pkinit_authData9,
2N/A "id-pkcs7-data", "PKCS7 data");
2N/A#else
2N/A /* See note in pkinit_pkcs7type2oid() */
2N/A ctx->id_pkinit_authData9 = NULL;
2N/A#endif
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.2", id_ms_kp_sc_logon,
2N/A "id-ms-kp-sc-logon EKU", "Microsoft SmartCard Login EKU");
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.3", id_ms_san_upn,
2N/A "id-ms-san-upn", "Microsoft Universal Principal Name");
2N/A
2N/A CREATE_OBJ_IF_NEEDED("1.3.6.1.5.5.7.3.1", id_kp_serverAuth,
2N/A "id-kp-serverAuth EKU", "Server Authentication EKU");
2N/A
2N/A /* Success */
2N/A retval = 0;
2N/A
2N/A pkinit_oids_refs++;
2N/A /* Solaris Kerberos */
2N/A k5_mutex_unlock(&oids_mutex);
2N/A
2N/Aout:
2N/A return retval;
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Aget_cert(char *filename, X509 **retcert)
2N/A{
2N/A X509 *cert = NULL;
2N/A BIO *tmp = NULL;
2N/A int code;
2N/A krb5_error_code retval;
2N/A
2N/A if (filename == NULL || retcert == NULL)
2N/A return EINVAL;
2N/A
2N/A *retcert = NULL;
2N/A
2N/A tmp = BIO_new(BIO_s_file());
2N/A if (tmp == NULL)
2N/A return ENOMEM;
2N/A
2N/A code = BIO_read_filename(tmp, filename);
2N/A if (code == 0) {
2N/A retval = errno;
2N/A goto cleanup;
2N/A }
2N/A
2N/A cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL);
2N/A if (cert == NULL) {
2N/A retval = EIO;
2N/A pkiDebug("failed to read certificate from %s\n", filename);
2N/A goto cleanup;
2N/A }
2N/A *retcert = cert;
2N/A retval = 0;
2N/Acleanup:
2N/A if (tmp != NULL)
2N/A BIO_free(tmp);
2N/A return retval;
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Aget_key(char *filename, EVP_PKEY **retkey)
2N/A{
2N/A EVP_PKEY *pkey = NULL;
2N/A BIO *tmp = NULL;
2N/A int code;
2N/A krb5_error_code retval;
2N/A
2N/A if (filename == NULL || retkey == NULL)
2N/A return EINVAL;
2N/A
2N/A tmp = BIO_new(BIO_s_file());
2N/A if (tmp == NULL)
2N/A return ENOMEM;
2N/A
2N/A code = BIO_read_filename(tmp, filename);
2N/A if (code == 0) {
2N/A retval = errno;
2N/A goto cleanup;
2N/A }
2N/A pkey = (EVP_PKEY *) PEM_read_bio_PrivateKey(tmp, NULL, NULL, NULL);
2N/A if (pkey == NULL) {
2N/A retval = EIO;
2N/A pkiDebug("failed to read private key from %s\n", filename);
2N/A goto cleanup;
2N/A }
2N/A *retkey = pkey;
2N/A retval = 0;
2N/Acleanup:
2N/A if (tmp != NULL)
2N/A BIO_free(tmp);
2N/A return retval;
2N/A}
2N/A
2N/Astatic void
2N/Apkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
2N/A{
2N/A if (ctx == NULL)
2N/A return;
2N/A
2N/A /* Only call OBJ_cleanup once! */
2N/A /* Solaris Kerberos: locking */
2N/A k5_mutex_lock(&oids_mutex);
2N/A if (--pkinit_oids_refs == 0)
2N/A OBJ_cleanup();
2N/A k5_mutex_unlock(&oids_mutex);
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Apkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
2N/A{
2N/A krb5_error_code retval = ENOMEM;
2N/A
2N/A plgctx->dh_1024 = DH_new();
2N/A if (plgctx->dh_1024 == NULL)
2N/A goto cleanup;
2N/A plgctx->dh_1024->p = BN_bin2bn(pkinit_1024_dhprime,
2N/A sizeof(pkinit_1024_dhprime), NULL);
2N/A if ((plgctx->dh_1024->g = BN_new()) == NULL ||
2N/A (plgctx->dh_1024->q = BN_new()) == NULL)
2N/A goto cleanup;
2N/A BN_set_word(plgctx->dh_1024->g, DH_GENERATOR_2);
2N/A BN_rshift1(plgctx->dh_1024->q, plgctx->dh_1024->p);
2N/A
2N/A plgctx->dh_2048 = DH_new();
2N/A if (plgctx->dh_2048 == NULL)
2N/A goto cleanup;
2N/A plgctx->dh_2048->p = BN_bin2bn(pkinit_2048_dhprime,
2N/A sizeof(pkinit_2048_dhprime), NULL);
2N/A if ((plgctx->dh_2048->g = BN_new()) == NULL ||
2N/A (plgctx->dh_2048->q = BN_new()) == NULL)
2N/A goto cleanup;
2N/A BN_set_word(plgctx->dh_2048->g, DH_GENERATOR_2);
2N/A BN_rshift1(plgctx->dh_2048->q, plgctx->dh_2048->p);
2N/A
2N/A plgctx->dh_4096 = DH_new();
2N/A if (plgctx->dh_4096 == NULL)
2N/A goto cleanup;
2N/A plgctx->dh_4096->p = BN_bin2bn(pkinit_4096_dhprime,
2N/A sizeof(pkinit_4096_dhprime), NULL);
2N/A if ((plgctx->dh_4096->g = BN_new()) == NULL ||
2N/A (plgctx->dh_4096->q = BN_new()) == NULL)
2N/A goto cleanup;
2N/A BN_set_word(plgctx->dh_4096->g, DH_GENERATOR_2);
2N/A BN_rshift1(plgctx->dh_4096->q, plgctx->dh_4096->p);
2N/A
2N/A retval = 0;
2N/A
2N/Acleanup:
2N/A if (retval)
2N/A pkinit_fini_dh_params(plgctx);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Astatic void
2N/Apkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
2N/A{
2N/A if (plgctx->dh_1024 != NULL)
2N/A DH_free(plgctx->dh_1024);
2N/A if (plgctx->dh_2048 != NULL)
2N/A DH_free(plgctx->dh_2048);
2N/A if (plgctx->dh_4096 != NULL)
2N/A DH_free(plgctx->dh_4096);
2N/A
2N/A plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Apkinit_init_certs(pkinit_identity_crypto_context ctx)
2N/A{
2N/A /* Solaris Kerberos */
2N/A int i;
2N/A
2N/A for (i = 0; i < MAX_CREDS_ALLOWED; i++)
2N/A ctx->creds[i] = NULL;
2N/A ctx->my_certs = NULL;
2N/A ctx->cert_index = 0;
2N/A ctx->my_key = NULL;
2N/A ctx->trustedCAs = NULL;
2N/A ctx->intermediateCAs = NULL;
2N/A ctx->revoked = NULL;
2N/A
2N/A return 0;
2N/A}
2N/A
2N/Astatic void
2N/Apkinit_fini_certs(pkinit_identity_crypto_context ctx)
2N/A{
2N/A if (ctx == NULL)
2N/A return;
2N/A
2N/A if (ctx->my_certs != NULL)
2N/A sk_X509_pop_free(ctx->my_certs, X509_free);
2N/A
2N/A if (ctx->my_key != NULL)
2N/A EVP_PKEY_free(ctx->my_key);
2N/A
2N/A if (ctx->trustedCAs != NULL)
2N/A sk_X509_pop_free(ctx->trustedCAs, X509_free);
2N/A
2N/A if (ctx->intermediateCAs != NULL)
2N/A sk_X509_pop_free(ctx->intermediateCAs, X509_free);
2N/A
2N/A if (ctx->revoked != NULL)
2N/A sk_X509_CRL_pop_free(ctx->revoked, X509_CRL_free);
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Apkinit_init_pkcs11(pkinit_identity_crypto_context ctx)
2N/A{
2N/A /* Solaris Kerberos */
2N/A
2N/A#ifndef WITHOUT_PKCS11
2N/A ctx->p11_module_name = strdup(PKCS11_MODNAME);
2N/A if (ctx->p11_module_name == NULL)
2N/A return ENOMEM;
2N/A ctx->p11_module = NULL;
2N/A ctx->slotid = PK_NOSLOT;
2N/A ctx->token_label = NULL;
2N/A ctx->cert_label = NULL;
2N/A ctx->PIN = NULL;
2N/A ctx->session = CK_INVALID_HANDLE;
2N/A ctx->p11 = NULL;
2N/A ctx->p11flags = 0; /* Solaris Kerberos */
2N/A#endif
2N/A ctx->pkcs11_method = 0;
2N/A (void) memset(ctx->creds, 0, sizeof(ctx->creds));
2N/A
2N/A return 0;
2N/A}
2N/A
2N/Astatic void
2N/Apkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
2N/A{
2N/A#ifndef WITHOUT_PKCS11
2N/A if (ctx == NULL)
2N/A return;
2N/A
2N/A if (ctx->p11 != NULL) {
2N/A if (ctx->session != CK_INVALID_HANDLE) {
2N/A ctx->p11->C_CloseSession(ctx->session);
2N/A ctx->session = CK_INVALID_HANDLE;
2N/A }
2N/A /*
2N/A * Solaris Kerberos:
2N/A * Only call C_Finalize if the process was not already using pkcs11.
2N/A */
2N/A if (ctx->finalize_pkcs11 == TRUE)
2N/A ctx->p11->C_Finalize(NULL_PTR);
2N/A
2N/A ctx->p11 = NULL;
2N/A }
2N/A if (ctx->p11_module != NULL) {
2N/A pkinit_C_UnloadModule(ctx->p11_module);
2N/A ctx->p11_module = NULL;
2N/A }
2N/A if (ctx->p11_module_name != NULL)
2N/A free(ctx->p11_module_name);
2N/A if (ctx->token_label != NULL)
2N/A free(ctx->token_label);
2N/A if (ctx->cert_id != NULL)
2N/A free(ctx->cert_id);
2N/A if (ctx->cert_label != NULL)
2N/A free(ctx->cert_label);
2N/A if (ctx->PIN != NULL) {
2N/A (void) memset(ctx->PIN, 0, strlen(ctx->PIN));
2N/A free(ctx->PIN);
2N/A }
2N/A#endif
2N/A}
2N/A
2N/Akrb5_error_code
2N/Apkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_prompter_fct prompter,
2N/A void *prompter_data)
2N/A{
2N/A id_cryptoctx->prompter = prompter;
2N/A id_cryptoctx->prompter_data = prompter_data;
2N/A
2N/A return 0;
2N/A}
2N/A
2N/A/*helper function for creating pkinit ContentInfo*/
2N/Astatic krb5_error_code
2N/Acreate_contentinfo(krb5_context context,
2N/A pkinit_plg_crypto_context plg_crypto_context,
2N/A ASN1_OBJECT *oid, unsigned char *data, size_t data_len,
2N/A PKCS7 **out_p7)
2N/A{
2N/A krb5_error_code retval = EINVAL;
2N/A PKCS7 *inner_p7;
2N/A ASN1_TYPE *pkinit_data = NULL;
2N/A
2N/A *out_p7 = NULL;
2N/A if ((inner_p7 = PKCS7_new()) == NULL)
2N/A goto cleanup;
2N/A if ((pkinit_data = ASN1_TYPE_new()) == NULL)
2N/A goto cleanup;
2N/A pkinit_data->type = V_ASN1_OCTET_STRING;
2N/A if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
2N/A goto cleanup;
2N/A if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string,
2N/A (unsigned char *) data, data_len)) {
2N/A unsigned long err = ERR_peek_error();
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("failed to add pkcs7 data\n");
2N/A goto cleanup;
2N/A }
2N/A if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
2N/A goto cleanup;
2N/A retval = 0;
2N/A *out_p7 = inner_p7;
2N/A inner_p7 = NULL;
2N/A pkinit_data = NULL;
2N/Acleanup:
2N/A if (inner_p7)
2N/A PKCS7_free(inner_p7);
2N/A if (pkinit_data)
2N/A ASN1_TYPE_free(pkinit_data);
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Acms_contentinfo_create(krb5_context context, /* IN */
2N/A pkinit_plg_crypto_context plg_cryptoctx, /* IN */
2N/A pkinit_req_crypto_context req_cryptoctx, /* IN */
2N/A pkinit_identity_crypto_context id_cryptoctx, /* IN */
2N/A int cms_msg_type,
2N/A unsigned char *data, unsigned int data_len,
2N/A unsigned char **out_data, unsigned int *out_data_len)
2N/A{
2N/A krb5_error_code retval = ENOMEM;
2N/A ASN1_OBJECT *oid = NULL;
2N/A PKCS7 *p7 = NULL;
2N/A unsigned char *p;
2N/A
2N/A /* Pick the correct oid for the eContentInfo. */
2N/A oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
2N/A if (oid == NULL)
2N/A goto cleanup;
2N/A retval = create_contentinfo(context, plg_cryptoctx, oid,
2N/A data, data_len, &p7);
2N/A if (retval != 0)
2N/A goto cleanup;
2N/A *out_data_len = i2d_PKCS7(p7, NULL);
2N/A if (!(*out_data_len)) {
2N/A unsigned long err = ERR_peek_error();
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("failed to der encode pkcs7\n");
2N/A goto cleanup;
2N/A }
2N/A retval = ENOMEM;
2N/A if ((p = *out_data = malloc(*out_data_len)) == NULL)
2N/A goto cleanup;
2N/A
2N/A /* DER encode PKCS7 data */
2N/A retval = i2d_PKCS7(p7, &p);
2N/A if (!retval) {
2N/A unsigned long err = ERR_peek_error();
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("failed to der encode pkcs7\n");
2N/A goto cleanup;
2N/A }
2N/A retval = 0;
2N/Acleanup:
2N/A if (p7)
2N/A PKCS7_free(p7);
2N/A if (oid)
2N/A ASN1_OBJECT_free(oid);
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acms_signeddata_create(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A int cms_msg_type,
2N/A int include_certchain,
2N/A unsigned char *data,
2N/A unsigned int data_len,
2N/A unsigned char **signed_data,
2N/A unsigned int *signed_data_len)
2N/A{
2N/A /* Solaris Kerberos */
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A PKCS7 *p7 = NULL, *inner_p7 = NULL;
2N/A PKCS7_SIGNED *p7s = NULL;
2N/A PKCS7_SIGNER_INFO *p7si = NULL;
2N/A unsigned char *p;
2N/A ASN1_TYPE *pkinit_data = NULL;
2N/A STACK_OF(X509) * cert_stack = NULL;
2N/A ASN1_OCTET_STRING *digest_attr = NULL;
2N/A EVP_MD_CTX ctx, ctx2;
2N/A const EVP_MD *md_tmp = NULL;
2N/A unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
2N/A unsigned char *digestInfo_buf = NULL, *abuf = NULL;
2N/A unsigned int md_len, md_len2, alen, digestInfo_len;
2N/A STACK_OF(X509_ATTRIBUTE) * sk;
2N/A unsigned char *sig = NULL;
2N/A unsigned int sig_len = 0;
2N/A X509_ALGOR *alg = NULL;
2N/A ASN1_OCTET_STRING *digest = NULL;
2N/A unsigned int alg_len = 0, digest_len = 0;
2N/A unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
2N/A X509 *cert = NULL;
2N/A ASN1_OBJECT *oid = NULL;
2N/A
2N/A /* Solaris Kerberos */
2N/A if (signed_data == NULL)
2N/A return EINVAL;
2N/A
2N/A if (signed_data_len == NULL)
2N/A return EINVAL;
2N/A
2N/A /* start creating PKCS7 data */
2N/A if ((p7 = PKCS7_new()) == NULL)
2N/A goto cleanup;
2N/A p7->type = OBJ_nid2obj(NID_pkcs7_signed);
2N/A
2N/A if ((p7s = PKCS7_SIGNED_new()) == NULL)
2N/A goto cleanup;
2N/A p7->d.sign = p7s;
2N/A if (!ASN1_INTEGER_set(p7s->version, 3))
2N/A goto cleanup;
2N/A
2N/A /* create a cert chain that has at least the signer's certificate */
2N/A if ((cert_stack = sk_X509_new_null()) == NULL)
2N/A goto cleanup;
2N/A
2N/A cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
2N/A if (!include_certchain) {
2N/A pkiDebug("only including signer's certificate\n");
2N/A sk_X509_push(cert_stack, X509_dup(cert));
2N/A } else {
2N/A /* create a cert chain */
2N/A X509_STORE *certstore = NULL;
2N/A X509_STORE_CTX certctx;
2N/A STACK_OF(X509) *certstack = NULL;
2N/A char buf[DN_BUF_LEN];
2N/A int i = 0, size = 0;
2N/A
2N/A if ((certstore = X509_STORE_new()) == NULL)
2N/A goto cleanup;
2N/A pkiDebug("building certificate chain\n");
2N/A X509_STORE_set_verify_cb_func(certstore, openssl_callback);
2N/A X509_STORE_CTX_init(&certctx, certstore, cert,
2N/A id_cryptoctx->intermediateCAs);
2N/A X509_STORE_CTX_trusted_stack(&certctx, id_cryptoctx->trustedCAs);
2N/A /* Solaris Kerberos */
2N/A if (X509_verify_cert(&certctx) <= 0) {
2N/A pkiDebug("failed to create a certificate chain: %s\n",
2N/A X509_verify_cert_error_string(X509_STORE_CTX_get_error(&certctx)));
2N/A if (!sk_X509_num(id_cryptoctx->trustedCAs))
2N/A pkiDebug("No trusted CAs found. Check your X509_anchors\n");
2N/A goto cleanup;
2N/A }
2N/A certstack = X509_STORE_CTX_get1_chain(&certctx);
2N/A size = sk_X509_num(certstack);
2N/A pkiDebug("size of certificate chain = %d\n", size);
2N/A for(i = 0; i < size - 1; i++) {
2N/A X509 *x = sk_X509_value(certstack, i);
2N/A X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
2N/A pkiDebug("cert #%d: %s\n", i, buf);
2N/A sk_X509_push(cert_stack, X509_dup(x));
2N/A }
2N/A X509_STORE_CTX_cleanup(&certctx);
2N/A X509_STORE_free(certstore);
2N/A sk_X509_pop_free(certstack, X509_free);
2N/A }
2N/A p7s->cert = cert_stack;
2N/A
2N/A /* fill-in PKCS7_SIGNER_INFO */
2N/A if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
2N/A goto cleanup;
2N/A if (!ASN1_INTEGER_set(p7si->version, 1))
2N/A goto cleanup;
2N/A if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
2N/A X509_get_issuer_name(cert)))
2N/A goto cleanup;
2N/A /* because ASN1_INTEGER_set is used to set a 'long' we will do
2N/A * things the ugly way. */
2N/A M_ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
2N/A if (!(p7si->issuer_and_serial->serial =
2N/A M_ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
2N/A goto cleanup;
2N/A
2N/A /* will not fill-out EVP_PKEY because it's on the smartcard */
2N/A
2N/A /* Set digest algs */
2N/A p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
2N/A
2N/A if (p7si->digest_alg->parameter != NULL)
2N/A ASN1_TYPE_free(p7si->digest_alg->parameter);
2N/A if ((p7si->digest_alg->parameter = ASN1_TYPE_new()) == NULL)
2N/A goto cleanup;
2N/A p7si->digest_alg->parameter->type = V_ASN1_NULL;
2N/A
2N/A /* Set sig algs */
2N/A if (p7si->digest_enc_alg->parameter != NULL)
2N/A ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
2N/A p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
2N/A if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
2N/A goto cleanup;
2N/A p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
2N/A
2N/A /* pick the correct oid for the eContentInfo */
2N/A oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
2N/A if (oid == NULL)
2N/A goto cleanup;
2N/A
2N/A if (cms_msg_type == CMS_SIGN_DRAFT9) {
2N/A /* don't include signed attributes for pa-type 15 request */
2N/A abuf = data;
2N/A alen = data_len;
2N/A } else {
2N/A /* add signed attributes */
2N/A /* compute sha1 digest over the EncapsulatedContentInfo */
2N/A EVP_MD_CTX_init(&ctx);
2N/A EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
2N/A EVP_DigestUpdate(&ctx, data, data_len);
2N/A md_tmp = EVP_MD_CTX_md(&ctx);
2N/A EVP_DigestFinal_ex(&ctx, md_data, &md_len);
2N/A
2N/A /* create a message digest attr */
2N/A digest_attr = ASN1_OCTET_STRING_new();
2N/A ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
2N/A PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
2N/A V_ASN1_OCTET_STRING, (char *) digest_attr);
2N/A
2N/A /* create a content-type attr */
2N/A PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
2N/A V_ASN1_OBJECT, oid);
2N/A
2N/A /* create the signature over signed attributes. get DER encoded value */
2N/A /* This is the place where smartcard signature needs to be calculated */
2N/A sk = p7si->auth_attr;
2N/A alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
2N/A ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
2N/A if (abuf == NULL)
2N/A goto cleanup2;
2N/A }
2N/A
2N/A#ifndef WITHOUT_PKCS11
2N/A /* Some tokens can only do RSAEncryption without sha1 hash */
2N/A /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
2N/A * function and the hash value into an ASN.1 value of type DigestInfo
2N/A * DigestInfo::=SEQUENCE {
2N/A * digestAlgorithm AlgorithmIdentifier,
2N/A * digest OCTET STRING }
2N/A */
2N/A if (id_cryptoctx->pkcs11_method == 1 &&
2N/A id_cryptoctx->mech == CKM_RSA_PKCS) {
2N/A pkiDebug("mech = CKM_RSA_PKCS\n");
2N/A EVP_MD_CTX_init(&ctx2);
2N/A /* if this is not draft9 request, include digest signed attribute */
2N/A if (cms_msg_type != CMS_SIGN_DRAFT9)
2N/A EVP_DigestInit_ex(&ctx2, md_tmp, NULL);
2N/A else
2N/A EVP_DigestInit_ex(&ctx2, EVP_sha1(), NULL);
2N/A EVP_DigestUpdate(&ctx2, abuf, alen);
2N/A EVP_DigestFinal_ex(&ctx2, md_data2, &md_len2);
2N/A
2N/A alg = X509_ALGOR_new();
2N/A if (alg == NULL)
2N/A goto cleanup2;
2N/A alg->algorithm = OBJ_nid2obj(NID_sha1);
2N/A alg->parameter = NULL;
2N/A alg_len = i2d_X509_ALGOR(alg, NULL);
2N/A alg_buf = (unsigned char *)malloc(alg_len);
2N/A if (alg_buf == NULL)
2N/A goto cleanup2;
2N/A
2N/A digest = ASN1_OCTET_STRING_new();
2N/A if (digest == NULL)
2N/A goto cleanup2;
2N/A ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
2N/A digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
2N/A digest_buf = (unsigned char *)malloc(digest_len);
2N/A if (digest_buf == NULL)
2N/A goto cleanup2;
2N/A
2N/A digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
2N/A V_ASN1_SEQUENCE);
2N/A y = digestInfo_buf = (unsigned char *)malloc(digestInfo_len);
2N/A if (digestInfo_buf == NULL)
2N/A goto cleanup2;
2N/A ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
2N/A V_ASN1_UNIVERSAL);
2N/A i2d_X509_ALGOR(alg, &y);
2N/A i2d_ASN1_OCTET_STRING(digest, &y);
2N/A#ifdef DEBUG_SIG
2N/A pkiDebug("signing buffer\n");
2N/A print_buffer(digestInfo_buf, digestInfo_len);
2N/A print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
2N/A#endif
2N/A retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
2N/A digestInfo_len, &sig, &sig_len);
2N/A } else
2N/A#endif
2N/A {
2N/A pkiDebug("mech = %s\n",
2N/A id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
2N/A retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
2N/A &sig, &sig_len);
2N/A }
2N/A#ifdef DEBUG_SIG
2N/A print_buffer(sig, sig_len);
2N/A#endif
2N/A if (cms_msg_type != CMS_SIGN_DRAFT9)
2N/A free(abuf);
2N/A if (retval)
2N/A goto cleanup2;
2N/A
2N/A /* Add signature */
2N/A if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig,
2N/A (int)sig_len)) {
2N/A unsigned long err = ERR_peek_error();
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("failed to add a signed digest attribute\n");
2N/A goto cleanup2;
2N/A }
2N/A /* adder signer_info to pkcs7 signed */
2N/A if (!PKCS7_add_signer(p7, p7si))
2N/A goto cleanup2;
2N/A
2N/A /* start on adding data to the pkcs7 signed */
2N/A if ((inner_p7 = PKCS7_new()) == NULL)
2N/A goto cleanup2;
2N/A if ((pkinit_data = ASN1_TYPE_new()) == NULL)
2N/A goto cleanup2;
2N/A pkinit_data->type = V_ASN1_OCTET_STRING;
2N/A if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
2N/A goto cleanup2;
2N/A if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
2N/A (int)data_len)) {
2N/A unsigned long err = ERR_peek_error();
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("failed to add pkcs7 data\n");
2N/A goto cleanup2;
2N/A }
2N/A
2N/A if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
2N/A goto cleanup2;
2N/A
2N/A if (p7s->contents != NULL)
2N/A PKCS7_free(p7s->contents);
2N/A p7s->contents = inner_p7;
2N/A
2N/A *signed_data_len = i2d_PKCS7(p7, NULL);
2N/A if (!(*signed_data_len)) {
2N/A unsigned long err = ERR_peek_error();
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("failed to der encode pkcs7\n");
2N/A goto cleanup2;
2N/A }
2N/A if ((p = *signed_data =
2N/A (unsigned char *) malloc((size_t)*signed_data_len)) == NULL)
2N/A goto cleanup2;
2N/A
2N/A /* DER encode PKCS7 data */
2N/A retval = i2d_PKCS7(p7, &p);
2N/A if (!retval) {
2N/A unsigned long err = ERR_peek_error();
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("failed to der encode pkcs7\n");
2N/A goto cleanup2;
2N/A }
2N/A retval = 0;
2N/A
2N/A#ifdef DEBUG_ASN1
2N/A if (cms_msg_type == CMS_SIGN_CLIENT) {
2N/A print_buffer_bin(*signed_data, *signed_data_len,
2N/A "/tmp/client_pkcs7_signeddata");
2N/A } else {
2N/A if (cms_msg_type == CMS_SIGN_SERVER) {
2N/A print_buffer_bin(*signed_data, *signed_data_len,
2N/A "/tmp/kdc_pkcs7_signeddata");
2N/A } else {
2N/A print_buffer_bin(*signed_data, *signed_data_len,
2N/A "/tmp/draft9_pkcs7_signeddata");
2N/A }
2N/A }
2N/A#endif
2N/A
2N/A cleanup2:
2N/A if (cms_msg_type != CMS_SIGN_DRAFT9)
2N/A EVP_MD_CTX_cleanup(&ctx);
2N/A#ifndef WITHOUT_PKCS11
2N/A if (id_cryptoctx->pkcs11_method == 1 &&
2N/A id_cryptoctx->mech == CKM_RSA_PKCS) {
2N/A EVP_MD_CTX_cleanup(&ctx2);
2N/A if (digest_buf != NULL)
2N/A free(digest_buf);
2N/A if (digestInfo_buf != NULL)
2N/A free(digestInfo_buf);
2N/A if (alg_buf != NULL)
2N/A free(alg_buf);
2N/A if (digest != NULL)
2N/A ASN1_OCTET_STRING_free(digest);
2N/A }
2N/A#endif
2N/A if (alg != NULL)
2N/A X509_ALGOR_free(alg);
2N/A cleanup:
2N/A if (p7 != NULL)
2N/A PKCS7_free(p7);
2N/A if (sig != NULL)
2N/A free(sig);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Acms_signeddata_verify(krb5_context context,
2N/A pkinit_plg_crypto_context plgctx,
2N/A pkinit_req_crypto_context reqctx,
2N/A pkinit_identity_crypto_context idctx,
2N/A int cms_msg_type,
2N/A int require_crl_checking,
2N/A unsigned char *signed_data,
2N/A unsigned int signed_data_len,
2N/A unsigned char **data,
2N/A unsigned int *data_len,
2N/A unsigned char **authz_data,
2N/A unsigned int *authz_data_len,
2N/A int *is_signed)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A CMS_ContentInfo *cms = NULL;
2N/A BIO *out = NULL;
2N/A int flags = CMS_NO_SIGNER_CERT_VERIFY;
2N/A unsigned int i = 0;
2N/A /* Solaris Kerberos */
2N/A int ret;
2N/A unsigned int vflags = 0, size = 0;
2N/A const unsigned char *p = signed_data;
2N/A STACK_OF(CMS_SignerInfo) *si_sk = NULL;
2N/A CMS_SignerInfo *si = NULL;
2N/A X509 *x = NULL;
2N/A X509_STORE *store = NULL;
2N/A X509_STORE_CTX cert_ctx;
2N/A STACK_OF(X509) *signerCerts = NULL;
2N/A STACK_OF(X509) *intermediateCAs = NULL;
2N/A STACK_OF(X509_CRL) *signerRevoked = NULL;
2N/A STACK_OF(X509_CRL) *revoked = NULL;
2N/A STACK_OF(X509) *verified_chain = NULL;
2N/A ASN1_OBJECT *oid = NULL;
2N/A const ASN1_OBJECT *type = NULL, *etype = NULL;
2N/A ASN1_OCTET_STRING **octets;
2N/A krb5_external_principal_identifier **krb5_verified_chain = NULL;
2N/A krb5_data *authz = NULL;
2N/A char buf[DN_BUF_LEN];
2N/A
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin(signed_data, signed_data_len,
2N/A "/tmp/client_received_pkcs7_signeddata");
2N/A#endif
2N/A if (is_signed)
2N/A *is_signed = 1;
2N/A /* Do this early enough to create the shadow OID for pkcs7-data if needed */
2N/A oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
2N/A if (oid == NULL)
2N/A goto cleanup;
2N/A
2N/A /* decode received CMS message */
2N/A if ((cms = d2i_CMS_ContentInfo(NULL, &p, (int)signed_data_len)) == NULL) {
2N/A unsigned long err = ERR_peek_error();
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("%s: failed to decode message: %s\n",
2N/A __FUNCTION__, ERR_error_string(err, NULL));
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* Handle the case in pkinit anonymous where we get unsigned data. */
2N/A type = CMS_get0_type(cms);
2N/A if (is_signed && !OBJ_cmp(type, oid)) {
2N/A unsigned char *d;
2N/A *is_signed = 0;
2N/A octets = CMS_get0_content(cms);
2N/A if (!octets || ((*octets)->type != V_ASN1_OCTET_STRING)) {
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A "Invalid pkinit packet: octet string "
2N/A "expected");
2N/A goto cleanup;
2N/A }
2N/A *data_len = ASN1_STRING_length(*octets);
2N/A d = malloc(*data_len);
2N/A if (d == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A memcpy(d, ASN1_STRING_data(*octets),
2N/A *data_len);
2N/A *data = d;
2N/A goto out;
2N/A } else {
2N/A /* Verify that the received message is CMS SignedData message. */
2N/A if (OBJ_obj2nid(type) != NID_pkcs7_signed) {
2N/A pkiDebug("Expected id-signedData CMS msg (received type = %d)\n",
2N/A OBJ_obj2nid(type));
2N/A krb5_set_error_message(context, retval, "wrong oid\n");
2N/A goto cleanup;
2N/A }
2N/A }
2N/A
2N/A /* setup to verify X509 certificate used to sign CMS message */
2N/A if (!(store = X509_STORE_new()))
2N/A goto cleanup;
2N/A
2N/A /* check if we are inforcing CRL checking */
2N/A vflags = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
2N/A if (require_crl_checking)
2N/A X509_STORE_set_verify_cb_func(store, openssl_callback);
2N/A else
2N/A X509_STORE_set_verify_cb_func(store, openssl_callback_ignore_crls);
2N/A X509_STORE_set_flags(store, vflags);
2N/A
2N/A /* get the signer's information from the CMS message */
2N/A CMS_set1_signers_certs(cms, NULL, 0);
2N/A if ((si_sk = CMS_get0_SignerInfos(cms)) == NULL)
2N/A goto cleanup;
2N/A if ((si = sk_CMS_SignerInfo_value(si_sk, 0)) == NULL)
2N/A goto cleanup;
2N/A pkinit_CMS_SignerInfo_get_cert(cms, si, &x);
2N/A if (x == NULL)
2N/A goto cleanup;
2N/A
2N/A /* create available CRL information (get local CRLs and include CRLs
2N/A * received in the CMS message
2N/A */
2N/A signerRevoked = CMS_get1_crls(cms);
2N/A if (idctx->revoked == NULL)
2N/A revoked = signerRevoked;
2N/A else if (signerRevoked == NULL)
2N/A revoked = idctx->revoked;
2N/A else {
2N/A size = sk_X509_CRL_num(idctx->revoked);
2N/A revoked = sk_X509_CRL_new_null();
2N/A for (i = 0; i < size; i++)
2N/A sk_X509_CRL_push(revoked, sk_X509_CRL_value(idctx->revoked, i));
2N/A size = sk_X509_CRL_num(signerRevoked);
2N/A for (i = 0; i < size; i++)
2N/A sk_X509_CRL_push(revoked, sk_X509_CRL_value(signerRevoked, i));
2N/A }
2N/A
2N/A /* create available intermediate CAs chains (get local intermediateCAs and
2N/A * include the CA chain received in the CMS message
2N/A */
2N/A signerCerts = CMS_get1_certs(cms);
2N/A if (idctx->intermediateCAs == NULL)
2N/A intermediateCAs = signerCerts;
2N/A else if (signerCerts == NULL)
2N/A intermediateCAs = idctx->intermediateCAs;
2N/A else {
2N/A size = sk_X509_num(idctx->intermediateCAs);
2N/A intermediateCAs = sk_X509_new_null();
2N/A for (i = 0; i < size; i++) {
2N/A sk_X509_push(intermediateCAs,
2N/A sk_X509_value(idctx->intermediateCAs, i));
2N/A }
2N/A size = sk_X509_num(signerCerts);
2N/A for (i = 0; i < size; i++) {
2N/A sk_X509_push(intermediateCAs, sk_X509_value(signerCerts, i));
2N/A }
2N/A }
2N/A
2N/A /* initialize x509 context with the received certificate and
2N/A * trusted and intermediate CA chains and CRLs
2N/A */
2N/A if (!X509_STORE_CTX_init(&cert_ctx, store, x, intermediateCAs))
2N/A goto cleanup;
2N/A
2N/A X509_STORE_CTX_set0_crls(&cert_ctx, revoked);
2N/A
2N/A /* add trusted CAs certificates for cert verification */
2N/A if (idctx->trustedCAs != NULL)
2N/A X509_STORE_CTX_trusted_stack(&cert_ctx, idctx->trustedCAs);
2N/A else {
2N/A pkiDebug("unable to find any trusted CAs\n");
2N/A goto cleanup;
2N/A }
2N/A#ifdef DEBUG_CERTCHAIN
2N/A if (intermediateCAs != NULL) {
2N/A size = sk_X509_num(intermediateCAs);
2N/A pkiDebug("untrusted cert chain of size %d\n", size);
2N/A for (i = 0; i < size; i++) {
2N/A X509_NAME_oneline(X509_get_subject_name(
2N/A sk_X509_value(intermediateCAs, i)), buf, sizeof(buf));
2N/A pkiDebug("cert #%d: %s\n", i, buf);
2N/A }
2N/A }
2N/A if (idctx->trustedCAs != NULL) {
2N/A size = sk_X509_num(idctx->trustedCAs);
2N/A pkiDebug("trusted cert chain of size %d\n", size);
2N/A for (i = 0; i < size; i++) {
2N/A X509_NAME_oneline(X509_get_subject_name(
2N/A sk_X509_value(idctx->trustedCAs, i)), buf, sizeof(buf));
2N/A pkiDebug("cert #%d: %s\n", i, buf);
2N/A }
2N/A }
2N/A if (revoked != NULL) {
2N/A size = sk_X509_CRL_num(revoked);
2N/A pkiDebug("CRL chain of size %d\n", size);
2N/A for (i = 0; i < size; i++) {
2N/A X509_CRL *crl = sk_X509_CRL_value(revoked, i);
2N/A X509_NAME_oneline(X509_CRL_get_issuer(crl), buf, sizeof(buf));
2N/A pkiDebug("crls by CA #%d: %s\n", i , buf);
2N/A }
2N/A }
2N/A#endif
2N/A
2N/A /* Solaris Kerberos */
2N/A ret = X509_verify_cert(&cert_ctx);
2N/A if (ret <= 0) {
2N/A int j = X509_STORE_CTX_get_error(&cert_ctx);
2N/A
2N/A reqctx->received_cert = X509_dup(cert_ctx.current_cert);
2N/A switch(j) {
2N/A case X509_V_ERR_CERT_REVOKED:
2N/A retval = KRB5KDC_ERR_REVOKED_CERTIFICATE;
2N/A break;
2N/A case X509_V_ERR_UNABLE_TO_GET_CRL:
2N/A retval = KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN;
2N/A break;
2N/A case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
2N/A case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
2N/A retval = KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE;
2N/A break;
2N/A default:
2N/A retval = KRB5KDC_ERR_INVALID_CERTIFICATE;
2N/A }
2N/A X509_NAME_oneline(X509_get_subject_name(
2N/A reqctx->received_cert), buf, sizeof(buf));
2N/A pkiDebug("problem with cert DN = %s (error=%d) %s\n", buf, j,
2N/A X509_verify_cert_error_string(j));
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A X509_verify_cert_error_string(j));
2N/A#ifdef DEBUG_CERTCHAIN
2N/A size = sk_X509_num(signerCerts);
2N/A pkiDebug("received cert chain of size %d\n", size);
2N/A for (j = 0; j < size; j++) {
2N/A X509 *tmp_cert = sk_X509_value(signerCerts, j);
2N/A X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, sizeof(buf));
2N/A pkiDebug("cert #%d: %s\n", j, buf);
2N/A }
2N/A#endif
2N/A } else {
2N/A /* retrieve verified certificate chain */
2N/A if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9)
2N/A verified_chain = X509_STORE_CTX_get1_chain(&cert_ctx);
2N/A }
2N/A X509_STORE_CTX_cleanup(&cert_ctx);
2N/A /* Solaris Kerberos */
2N/A if (ret <= 0)
2N/A goto cleanup;
2N/A
2N/A out = BIO_new(BIO_s_mem());
2N/A if (cms_msg_type == CMS_SIGN_DRAFT9)
2N/A flags |= CMS_NOATTR;
2N/A etype = CMS_get0_eContentType(cms);
2N/A if (CMS_verify(cms, NULL, store, NULL, out, flags)) {
2N/A int valid_oid = 0;
2N/A
2N/A if (!OBJ_cmp(etype, oid))
2N/A valid_oid = 1;
2N/A else if (cms_msg_type == CMS_SIGN_DRAFT9) {
2N/A /*
2N/A * Various implementations of the pa-type 15 request use
2N/A * different OIDS. We check that the returned object
2N/A * has any of the acceptable OIDs
2N/A */
2N/A ASN1_OBJECT *client_oid = NULL, *server_oid = NULL, *rsa_oid = NULL;
2N/A client_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_CLIENT);
2N/A server_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_SERVER);
2N/A rsa_oid = pkinit_pkcs7type2oid(plgctx, CMS_ENVEL_SERVER);
2N/A if (!OBJ_cmp(etype, client_oid) ||
2N/A !OBJ_cmp(etype, server_oid) ||
2N/A !OBJ_cmp(etype, rsa_oid))
2N/A valid_oid = 1;
2N/A }
2N/A
2N/A if (valid_oid)
2N/A pkiDebug("CMS Verification successful\n");
2N/A else {
2N/A pkiDebug("wrong oid in eContentType\n");
2N/A print_buffer(etype->data,
2N/A (unsigned int)etype->length);
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, retval, "wrong oid\n");
2N/A goto cleanup;
2N/A }
2N/A }
2N/A else {
2N/A unsigned long err = ERR_peek_error();
2N/A switch(ERR_GET_REASON(err)) {
2N/A case PKCS7_R_DIGEST_FAILURE:
2N/A retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
2N/A break;
2N/A case PKCS7_R_SIGNATURE_FAILURE:
2N/A default:
2N/A retval = KRB5KDC_ERR_INVALID_SIG;
2N/A }
2N/A pkiDebug("PKCS7 Verification failure\n");
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* transfer the data from CMS message into return buffer */
2N/A for (size = 0;;) {
2N/A int remain;
2N/A retval = ENOMEM;
2N/A if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
2N/A goto cleanup;
2N/A remain = BIO_read(out, &((*data)[size]), 1024 * 10);
2N/A if (remain <= 0)
2N/A break;
2N/A else
2N/A size += remain;
2N/A }
2N/A *data_len = size;
2N/A
2N/A reqctx->received_cert = X509_dup(x);
2N/A
2N/A /* generate authorization data */
2N/A if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9) {
2N/A
2N/A if (authz_data == NULL || authz_data_len == NULL)
2N/A goto out;
2N/A
2N/A *authz_data = NULL;
2N/A retval = create_identifiers_from_stack(verified_chain,
2N/A &krb5_verified_chain);
2N/A if (retval) {
2N/A pkiDebug("create_identifiers_from_stack failed\n");
2N/A goto cleanup;
2N/A }
2N/A
2N/A retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_verified_chain, &authz);
2N/A if (retval) {
2N/A pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
2N/A goto cleanup;
2N/A }
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin((unsigned char *)authz->data, authz->length,
2N/A "/tmp/kdc_ad_initial_verified_cas");
2N/A#endif
2N/A *authz_data = (unsigned char *)malloc(authz->length);
2N/A if (*authz_data == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A (void) memcpy(*authz_data, authz->data, authz->length);
2N/A *authz_data_len = authz->length;
2N/A }
2N/A out:
2N/A retval = 0;
2N/A
2N/A cleanup:
2N/A if (out != NULL)
2N/A BIO_free(out);
2N/A if (store != NULL)
2N/A X509_STORE_free(store);
2N/A if (cms != NULL) {
2N/A if (signerCerts != NULL)
2N/A pkinit_CMS_free1_certs(signerCerts);
2N/A if (idctx->intermediateCAs != NULL && signerCerts)
2N/A sk_X509_free(intermediateCAs);
2N/A if (signerRevoked != NULL)
2N/A pkinit_CMS_free1_crls(signerRevoked);
2N/A if (idctx->revoked != NULL && signerRevoked)
2N/A sk_X509_CRL_free(revoked);
2N/A CMS_ContentInfo_free(cms);
2N/A }
2N/A if (verified_chain != NULL)
2N/A sk_X509_pop_free(verified_chain, X509_free);
2N/A if (krb5_verified_chain != NULL)
2N/A free_krb5_external_principal_identifier(&krb5_verified_chain);
2N/A if (authz != NULL)
2N/A krb5_free_data(context, authz);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Acms_envelopeddata_create(krb5_context context,
2N/A pkinit_plg_crypto_context plgctx,
2N/A pkinit_req_crypto_context reqctx,
2N/A pkinit_identity_crypto_context idctx,
2N/A krb5_preauthtype pa_type,
2N/A int include_certchain,
2N/A unsigned char *key_pack,
2N/A unsigned int key_pack_len,
2N/A unsigned char **out,
2N/A unsigned int *out_len)
2N/A{
2N/A
2N/A /* Solaris Kerberos */
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A PKCS7 *p7 = NULL;
2N/A BIO *in = NULL;
2N/A unsigned char *p = NULL, *signed_data = NULL, *enc_data = NULL;
2N/A int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY;
2N/A STACK_OF(X509) *encerts = NULL;
2N/A const EVP_CIPHER *cipher = NULL;
2N/A int cms_msg_type;
2N/A
2N/A /* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */
2N/A switch ((int)pa_type) {
2N/A case KRB5_PADATA_PK_AS_REQ_OLD:
2N/A case KRB5_PADATA_PK_AS_REP_OLD:
2N/A cms_msg_type = CMS_SIGN_DRAFT9;
2N/A break;
2N/A case KRB5_PADATA_PK_AS_REQ:
2N/A cms_msg_type = CMS_ENVEL_SERVER;
2N/A break;
2N/A default:
2N/A /* Solaris Kerberos */
2N/A retval = EINVAL;
2N/A goto cleanup;
2N/A }
2N/A
2N/A retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
2N/A cms_msg_type, include_certchain, key_pack, key_pack_len,
2N/A &signed_data, (unsigned int *)&signed_data_len);
2N/A if (retval) {
2N/A pkiDebug("failed to create pkcs7 signed data\n");
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* check we have client's certificate */
2N/A if (reqctx->received_cert == NULL) {
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto cleanup;
2N/A }
2N/A encerts = sk_X509_new_null();
2N/A sk_X509_push(encerts, reqctx->received_cert);
2N/A
2N/A cipher = EVP_des_ede3_cbc();
2N/A in = BIO_new(BIO_s_mem());
2N/A switch (pa_type) {
2N/A case KRB5_PADATA_PK_AS_REQ:
2N/A prepare_enc_data(signed_data, signed_data_len, &enc_data,
2N/A &enc_data_len);
2N/A retval = BIO_write(in, enc_data, enc_data_len);
2N/A if (retval != enc_data_len) {
2N/A pkiDebug("BIO_write only wrote %d\n", retval);
2N/A goto cleanup;
2N/A }
2N/A break;
2N/A case KRB5_PADATA_PK_AS_REP_OLD:
2N/A case KRB5_PADATA_PK_AS_REQ_OLD:
2N/A retval = BIO_write(in, signed_data, signed_data_len);
2N/A if (retval != signed_data_len) {
2N/A pkiDebug("BIO_write only wrote %d\n", retval);
2N/A /* Solaris Kerberos */
2N/A retval = KRB5KRB_ERR_GENERIC;
2N/A goto cleanup;
2N/A }
2N/A break;
2N/A default:
2N/A retval = -1;
2N/A goto cleanup;
2N/A }
2N/A
2N/A p7 = PKCS7_encrypt(encerts, in, cipher, flags);
2N/A if (p7 == NULL) {
2N/A pkiDebug("failed to encrypt PKCS7 object\n");
2N/A retval = -1;
2N/A goto cleanup;
2N/A }
2N/A switch (pa_type) {
2N/A case KRB5_PADATA_PK_AS_REQ:
2N/A p7->d.enveloped->enc_data->content_type =
2N/A OBJ_nid2obj(NID_pkcs7_signed);
2N/A break;
2N/A case KRB5_PADATA_PK_AS_REP_OLD:
2N/A case KRB5_PADATA_PK_AS_REQ_OLD:
2N/A p7->d.enveloped->enc_data->content_type =
2N/A OBJ_nid2obj(NID_pkcs7_data);
2N/A break;
2N/A }
2N/A
2N/A *out_len = i2d_PKCS7(p7, NULL);
2N/A if (!*out_len || (p = *out = (unsigned char *)malloc(*out_len)) == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A retval = i2d_PKCS7(p7, &p);
2N/A if (!retval) {
2N/A pkiDebug("unable to write pkcs7 object\n");
2N/A goto cleanup;
2N/A }
2N/A retval = 0;
2N/A
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin(*out, *out_len, "/tmp/kdc_enveloped_data");
2N/A#endif
2N/A
2N/Acleanup:
2N/A if (p7 != NULL)
2N/A PKCS7_free(p7);
2N/A if (in != NULL)
2N/A BIO_free(in);
2N/A if (signed_data != NULL)
2N/A free(signed_data);
2N/A if (enc_data != NULL)
2N/A free(enc_data);
2N/A if (encerts != NULL)
2N/A sk_X509_free(encerts);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Acms_envelopeddata_verify(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_preauthtype pa_type,
2N/A int require_crl_checking,
2N/A unsigned char *enveloped_data,
2N/A unsigned int enveloped_data_len,
2N/A unsigned char **data,
2N/A unsigned int *data_len)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A PKCS7 *p7 = NULL;
2N/A BIO *out = NULL;
2N/A int i = 0;
2N/A unsigned int size = 0;
2N/A const unsigned char *p = enveloped_data;
2N/A unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0;
2N/A unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL;
2N/A int msg_type = 0;
2N/A
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin(enveloped_data, enveloped_data_len,
2N/A "/tmp/client_envelopeddata");
2N/A#endif
2N/A /* decode received PKCS7 message */
2N/A if ((p7 = d2i_PKCS7(NULL, &p, (int)enveloped_data_len)) == NULL) {
2N/A unsigned long err = ERR_peek_error();
2N/A pkiDebug("failed to decode pkcs7\n");
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* verify that the received message is PKCS7 EnvelopedData message */
2N/A if (OBJ_obj2nid(p7->type) != NID_pkcs7_enveloped) {
2N/A pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n",
2N/A OBJ_obj2nid(p7->type));
2N/A krb5_set_error_message(context, retval, "wrong oid\n");
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* decrypt received PKCS7 message */
2N/A out = BIO_new(BIO_s_mem());
2N/A if (pkcs7_decrypt(context, id_cryptoctx, p7, out)) {
2N/A pkiDebug("PKCS7 decryption successful\n");
2N/A } else {
2N/A unsigned long err = ERR_peek_error();
2N/A if (err != 0)
2N/A krb5_set_error_message(context, retval, "%s\n",
2N/A ERR_error_string(err, NULL));
2N/A pkiDebug("PKCS7 decryption failed\n");
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* transfer the decoded PKCS7 SignedData message into a separate buffer */
2N/A for (;;) {
2N/A if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL)
2N/A goto cleanup;
2N/A i = BIO_read(out, &(tmp_buf[size]), 1024 * 10);
2N/A if (i <= 0)
2N/A break;
2N/A else
2N/A size += i;
2N/A }
2N/A tmp_buf_len = size;
2N/A
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack");
2N/A#endif
2N/A /* verify PKCS7 SignedData message */
2N/A switch (pa_type) {
2N/A case KRB5_PADATA_PK_AS_REP:
2N/A msg_type = CMS_ENVEL_SERVER;
2N/A
2N/A break;
2N/A case KRB5_PADATA_PK_AS_REP_OLD:
2N/A msg_type = CMS_SIGN_DRAFT9;
2N/A break;
2N/A default:
2N/A pkiDebug("%s: unrecognized pa_type = %d\n", __FUNCTION__, pa_type);
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto cleanup;
2N/A }
2N/A /*
2N/A * If this is the RFC style, wrap the signed data to make
2N/A * decoding easier in the verify routine.
2N/A * For draft9-compatible, we don't do anything because it
2N/A * is already wrapped.
2N/A */
2N/A#ifdef LONGHORN_BETA_COMPAT
2N/A /*
2N/A * The Longhorn server returns the expected RFC-style data, but
2N/A * it is missing the sequence tag and length, so it requires
2N/A * special processing when wrapping.
2N/A * This will hopefully be fixed before the final release and
2N/A * this can all be removed.
2N/A */
2N/A if (msg_type == CMS_ENVEL_SERVER || longhorn == 1) {
2N/A retval = wrap_signeddata(tmp_buf, tmp_buf_len,
2N/A &tmp_buf2, &tmp_buf2_len, longhorn);
2N/A if (retval) {
2N/A pkiDebug("failed to encode signeddata\n");
2N/A goto cleanup;
2N/A }
2N/A vfy_buf = tmp_buf2;
2N/A vfy_buf_len = tmp_buf2_len;
2N/A
2N/A } else {
2N/A vfy_buf = tmp_buf;
2N/A vfy_buf_len = tmp_buf_len;
2N/A }
2N/A#else
2N/A if (msg_type == CMS_ENVEL_SERVER) {
2N/A retval = wrap_signeddata(tmp_buf, tmp_buf_len,
2N/A &tmp_buf2, &tmp_buf2_len);
2N/A if (retval) {
2N/A pkiDebug("failed to encode signeddata\n");
2N/A goto cleanup;
2N/A }
2N/A vfy_buf = tmp_buf2;
2N/A vfy_buf_len = tmp_buf2_len;
2N/A
2N/A } else {
2N/A vfy_buf = tmp_buf;
2N/A vfy_buf_len = tmp_buf_len;
2N/A }
2N/A#endif
2N/A
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2");
2N/A#endif
2N/A
2N/A retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx,
2N/A id_cryptoctx, msg_type,
2N/A require_crl_checking,
2N/A vfy_buf, vfy_buf_len,
2N/A data, data_len, NULL, NULL, NULL);
2N/A
2N/A if (!retval)
2N/A pkiDebug("PKCS7 Verification Success\n");
2N/A else {
2N/A pkiDebug("PKCS7 Verification Failure\n");
2N/A goto cleanup;
2N/A }
2N/A
2N/A retval = 0;
2N/A
2N/A cleanup:
2N/A
2N/A if (p7 != NULL)
2N/A PKCS7_free(p7);
2N/A if (out != NULL)
2N/A BIO_free(out);
2N/A if (tmp_buf != NULL)
2N/A free(tmp_buf);
2N/A if (tmp_buf2 != NULL)
2N/A free(tmp_buf2);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Acrypto_retrieve_X509_sans(krb5_context context,
2N/A pkinit_plg_crypto_context plgctx,
2N/A pkinit_req_crypto_context reqctx,
2N/A X509 *cert,
2N/A krb5_principal **princs_ret,
2N/A krb5_principal **upn_ret,
2N/A unsigned char ***dns_ret)
2N/A{
2N/A krb5_error_code retval = EINVAL;
2N/A char buf[DN_BUF_LEN];
2N/A int p = 0, u = 0, d = 0;
2N/A krb5_principal *princs = NULL;
2N/A krb5_principal *upns = NULL;
2N/A unsigned char **dnss = NULL;
2N/A int i, num_found = 0;
2N/A
2N/A if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
2N/A pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
2N/A return retval;
2N/A }
2N/A
2N/A if (cert == NULL) {
2N/A pkiDebug("%s: no certificate!\n", __FUNCTION__);
2N/A return retval;
2N/A }
2N/A
2N/A X509_NAME_oneline(X509_get_subject_name(cert),
2N/A buf, sizeof(buf));
2N/A pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf);
2N/A
2N/A if ((i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) >= 0) {
2N/A X509_EXTENSION *ext = NULL;
2N/A GENERAL_NAMES *ialt = NULL;
2N/A GENERAL_NAME *gen = NULL;
2N/A int ret = 0;
2N/A unsigned int num_sans = 0;
2N/A
2N/A if (!(ext = X509_get_ext(cert, i)) || !(ialt = X509V3_EXT_d2i(ext))) {
2N/A pkiDebug("%s: found no subject alt name extensions\n",
2N/A __FUNCTION__);
2N/A goto cleanup;
2N/A }
2N/A num_sans = sk_GENERAL_NAME_num(ialt);
2N/A
2N/A pkiDebug("%s: found %d subject alt name extension(s)\n",
2N/A __FUNCTION__, num_sans);
2N/A
2N/A /* OK, we're likely returning something. Allocate return values */
2N/A if (princs_ret != NULL) {
2N/A princs = calloc(num_sans + 1, sizeof(krb5_principal));
2N/A if (princs == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A }
2N/A if (upn_ret != NULL) {
2N/A upns = calloc(num_sans + 1, sizeof(krb5_principal));
2N/A if (upns == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A }
2N/A if (dns_ret != NULL) {
2N/A dnss = calloc(num_sans + 1, sizeof(*dnss));
2N/A if (dnss == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A }
2N/A
2N/A for (i = 0; i < num_sans; i++) {
2N/A krb5_data name = { 0, 0, NULL };
2N/A
2N/A gen = sk_GENERAL_NAME_value(ialt, i);
2N/A switch (gen->type) {
2N/A case GEN_OTHERNAME:
2N/A name.length = gen->d.otherName->value->value.sequence->length;
2N/A name.data = (char *)gen->d.otherName->value->value.sequence->data;
2N/A if (princs != NULL
2N/A && OBJ_cmp(plgctx->id_pkinit_san,
2N/A gen->d.otherName->type_id) == 0) {
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin((unsigned char *)name.data, name.length,
2N/A "/tmp/pkinit_san");
2N/A#endif
2N/A ret = k5int_decode_krb5_principal_name(&name, &princs[p]);
2N/A if (ret) {
2N/A pkiDebug("%s: failed decoding pkinit san value\n",
2N/A __FUNCTION__);
2N/A } else {
2N/A p++;
2N/A num_found++;
2N/A }
2N/A } else if (upns != NULL
2N/A && OBJ_cmp(plgctx->id_ms_san_upn,
2N/A gen->d.otherName->type_id) == 0) {
2N/A ret = krb5_parse_name(context, name.data, &upns[u]);
2N/A if (ret) {
2N/A pkiDebug("%s: failed parsing ms-upn san value\n",
2N/A __FUNCTION__);
2N/A } else {
2N/A u++;
2N/A num_found++;
2N/A }
2N/A } else {
2N/A pkiDebug("%s: unrecognized othername oid in SAN\n",
2N/A __FUNCTION__);
2N/A continue;
2N/A }
2N/A
2N/A break;
2N/A case GEN_DNS:
2N/A if (dnss != NULL) {
2N/A pkiDebug("%s: found dns name = %s\n",
2N/A __FUNCTION__, gen->d.dNSName->data);
2N/A dnss[d] = (unsigned char *)
2N/A strdup((char *)gen->d.dNSName->data);
2N/A if (dnss[d] == NULL) {
2N/A pkiDebug("%s: failed to duplicate dns name\n",
2N/A __FUNCTION__);
2N/A } else {
2N/A d++;
2N/A num_found++;
2N/A }
2N/A }
2N/A break;
2N/A default:
2N/A pkiDebug("%s: SAN type = %d expecting %d\n",
2N/A __FUNCTION__, gen->type, GEN_OTHERNAME);
2N/A }
2N/A }
2N/A sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
2N/A }
2N/A
2N/A retval = 0;
2N/A if (princs)
2N/A *princs_ret = princs;
2N/A if (upns)
2N/A *upn_ret = upns;
2N/A if (dnss)
2N/A *dns_ret = dnss;
2N/A
2N/A cleanup:
2N/A if (retval) {
2N/A if (princs != NULL) {
2N/A for (i = 0; princs[i] != NULL; i++)
2N/A krb5_free_principal(context, princs[i]);
2N/A free(princs);
2N/A }
2N/A if (upns != NULL) {
2N/A for (i = 0; upns[i] != NULL; i++)
2N/A krb5_free_principal(context, upns[i]);
2N/A free(upns);
2N/A }
2N/A if (dnss != NULL) {
2N/A for (i = 0; dnss[i] != NULL; i++)
2N/A free(dnss[i]);
2N/A free(dnss);
2N/A }
2N/A }
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_retrieve_cert_sans(krb5_context context,
2N/A pkinit_plg_crypto_context plgctx,
2N/A pkinit_req_crypto_context reqctx,
2N/A pkinit_identity_crypto_context idctx,
2N/A krb5_principal **princs_ret,
2N/A krb5_principal **upn_ret,
2N/A unsigned char ***dns_ret)
2N/A{
2N/A krb5_error_code retval = EINVAL;
2N/A
2N/A if (reqctx->received_cert == NULL) {
2N/A pkiDebug("%s: No certificate!\n", __FUNCTION__);
2N/A return retval;
2N/A }
2N/A
2N/A return crypto_retrieve_X509_sans(context, plgctx, reqctx,
2N/A reqctx->received_cert, princs_ret,
2N/A upn_ret, dns_ret);
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_check_cert_eku(krb5_context context,
2N/A pkinit_plg_crypto_context plgctx,
2N/A pkinit_req_crypto_context reqctx,
2N/A pkinit_identity_crypto_context idctx,
2N/A int checking_kdc_cert,
2N/A int allow_secondary_usage,
2N/A int *valid_eku)
2N/A{
2N/A char buf[DN_BUF_LEN];
2N/A int found_eku = 0;
2N/A krb5_error_code retval = EINVAL;
2N/A int i;
2N/A
2N/A /* Solaris Kerberos */
2N/A if (valid_eku == NULL)
2N/A return retval;
2N/A
2N/A *valid_eku = 0;
2N/A if (reqctx->received_cert == NULL)
2N/A goto cleanup;
2N/A
2N/A X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
2N/A buf, sizeof(buf));
2N/A pkiDebug("%s: looking for EKUs in cert = %s\n", __FUNCTION__, buf);
2N/A
2N/A if ((i = X509_get_ext_by_NID(reqctx->received_cert,
2N/A NID_ext_key_usage, -1)) >= 0) {
2N/A EXTENDED_KEY_USAGE *extusage;
2N/A
2N/A extusage = X509_get_ext_d2i(reqctx->received_cert, NID_ext_key_usage,
2N/A NULL, NULL);
2N/A if (extusage) {
2N/A pkiDebug("%s: found eku info in the cert\n", __FUNCTION__);
2N/A for (i = 0; found_eku == 0 && i < sk_ASN1_OBJECT_num(extusage); i++) {
2N/A ASN1_OBJECT *tmp_oid;
2N/A
2N/A tmp_oid = sk_ASN1_OBJECT_value(extusage, i);
2N/A pkiDebug("%s: checking eku %d of %d, allow_secondary = %d\n",
2N/A __FUNCTION__, i+1, sk_ASN1_OBJECT_num(extusage),
2N/A allow_secondary_usage);
2N/A if (checking_kdc_cert) {
2N/A if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPKdc) == 0)
2N/A || (allow_secondary_usage
2N/A && OBJ_cmp(tmp_oid, plgctx->id_kp_serverAuth) == 0))
2N/A found_eku = 1;
2N/A } else {
2N/A if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPClientAuth) == 0)
2N/A || (allow_secondary_usage
2N/A && OBJ_cmp(tmp_oid, plgctx->id_ms_kp_sc_logon) == 0))
2N/A found_eku = 1;
2N/A }
2N/A }
2N/A }
2N/A EXTENDED_KEY_USAGE_free(extusage);
2N/A
2N/A if (found_eku) {
2N/A ASN1_BIT_STRING *usage = NULL;
2N/A pkiDebug("%s: found acceptable EKU, checking for digitalSignature\n", __FUNCTION__);
2N/A
2N/A /* check that digitalSignature KeyUsage is present */
2N/A if ((usage = X509_get_ext_d2i(reqctx->received_cert,
2N/A NID_key_usage, NULL, NULL))) {
2N/A
2N/A if (!ku_reject(reqctx->received_cert,
2N/A X509v3_KU_DIGITAL_SIGNATURE)) {
2N/A pkiDebug("%s: found digitalSignature KU\n",
2N/A __FUNCTION__);
2N/A *valid_eku = 1;
2N/A } else
2N/A pkiDebug("%s: didn't find digitalSignature KU\n",
2N/A __FUNCTION__);
2N/A }
2N/A ASN1_BIT_STRING_free(usage);
2N/A }
2N/A }
2N/A retval = 0;
2N/Acleanup:
2N/A pkiDebug("%s: returning retval %d, valid_eku %d\n",
2N/A __FUNCTION__, retval, *valid_eku);
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Apkinit_octetstring2key(krb5_context context,
2N/A krb5_enctype etype,
2N/A unsigned char *key,
2N/A unsigned int dh_key_len,
2N/A krb5_keyblock * key_block)
2N/A{
2N/A krb5_error_code retval;
2N/A unsigned char *buf = NULL;
2N/A unsigned char md[SHA_DIGEST_LENGTH];
2N/A unsigned char counter;
2N/A size_t keybytes, keylength, offset;
2N/A krb5_data random_data;
2N/A
2N/A
2N/A if ((buf = (unsigned char *) malloc(dh_key_len)) == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A (void) memset(buf, 0, dh_key_len);
2N/A
2N/A counter = 0;
2N/A offset = 0;
2N/A do {
2N/A SHA_CTX c;
2N/A
2N/A SHA1_Init(&c);
2N/A SHA1_Update(&c, &counter, 1);
2N/A SHA1_Update(&c, key, dh_key_len);
2N/A SHA1_Final(md, &c);
2N/A
2N/A if (dh_key_len - offset < sizeof(md))
2N/A (void) memcpy(buf + offset, md, dh_key_len - offset);
2N/A else
2N/A (void) memcpy(buf + offset, md, sizeof(md));
2N/A
2N/A offset += sizeof(md);
2N/A counter++;
2N/A } while (offset < dh_key_len);
2N/A
2N/A /* Solaris Kerberos */
2N/A key_block->magic = KV5M_KEYBLOCK;
2N/A key_block->enctype = etype;
2N/A
2N/A retval = krb5_c_keylengths(context, etype, &keybytes, &keylength);
2N/A if (retval)
2N/A goto cleanup;
2N/A
2N/A key_block->length = keylength;
2N/A key_block->contents = calloc(keylength, sizeof(unsigned char *));
2N/A if (key_block->contents == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A random_data.length = keybytes;
2N/A random_data.data = (char *)buf;
2N/A
2N/A retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
2N/A
2N/A cleanup:
2N/A if (buf != NULL)
2N/A free(buf);
2N/A if (retval && key_block->contents != NULL && key_block->length != 0) {
2N/A (void) memset(key_block->contents, 0, key_block->length);
2N/A key_block->length = 0;
2N/A }
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Aclient_create_dh(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A int dh_size,
2N/A unsigned char **dh_params,
2N/A unsigned int *dh_params_len,
2N/A unsigned char **dh_pubkey,
2N/A unsigned int *dh_pubkey_len)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A unsigned char *buf = NULL;
2N/A int dh_err = 0;
2N/A ASN1_INTEGER *pub_key = NULL;
2N/A
2N/A if (cryptoctx->dh == NULL) {
2N/A if ((cryptoctx->dh = DH_new()) == NULL)
2N/A goto cleanup;
2N/A if ((cryptoctx->dh->g = BN_new()) == NULL ||
2N/A (cryptoctx->dh->q = BN_new()) == NULL)
2N/A goto cleanup;
2N/A
2N/A switch(dh_size) {
2N/A case 1024:
2N/A pkiDebug("client uses 1024 DH keys\n");
2N/A cryptoctx->dh->p = get_rfc2409_prime_1024(NULL);
2N/A break;
2N/A case 2048:
2N/A pkiDebug("client uses 2048 DH keys\n");
2N/A cryptoctx->dh->p = BN_bin2bn(pkinit_2048_dhprime,
2N/A sizeof(pkinit_2048_dhprime), NULL);
2N/A break;
2N/A case 4096:
2N/A pkiDebug("client uses 4096 DH keys\n");
2N/A cryptoctx->dh->p = BN_bin2bn(pkinit_4096_dhprime,
2N/A sizeof(pkinit_4096_dhprime), NULL);
2N/A break;
2N/A default:
2N/A goto cleanup;
2N/A }
2N/A
2N/A BN_set_word((cryptoctx->dh->g), DH_GENERATOR_2);
2N/A BN_rshift1(cryptoctx->dh->q, cryptoctx->dh->p);
2N/A }
2N/A
2N/A DH_generate_key(cryptoctx->dh);
2N/A/* Solaris Kerberos */
2N/A#ifdef DEBUG
2N/A DH_check(cryptoctx->dh, &dh_err);
2N/A if (dh_err != 0) {
2N/A pkiDebug("Warning: dh_check failed with %d\n", dh_err);
2N/A if (dh_err & DH_CHECK_P_NOT_PRIME)
2N/A pkiDebug("p value is not prime\n");
2N/A if (dh_err & DH_CHECK_P_NOT_SAFE_PRIME)
2N/A pkiDebug("p value is not a safe prime\n");
2N/A if (dh_err & DH_UNABLE_TO_CHECK_GENERATOR)
2N/A pkiDebug("unable to check the generator value\n");
2N/A if (dh_err & DH_NOT_SUITABLE_GENERATOR)
2N/A pkiDebug("the g value is not a generator\n");
2N/A }
2N/A#endif
2N/A#ifdef DEBUG_DH
2N/A print_dh(cryptoctx->dh, "client's DH params\n");
2N/A print_pubkey(cryptoctx->dh->pub_key, "client's pub_key=");
2N/A#endif
2N/A
2N/A DH_check_pub_key(cryptoctx->dh, cryptoctx->dh->pub_key, &dh_err);
2N/A if (dh_err != 0) {
2N/A pkiDebug("dh_check_pub_key failed with %d\n", dh_err);
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* pack DHparams */
2N/A /* aglo: usually we could just call i2d_DHparams to encode DH params
2N/A * however, PKINIT requires RFC3279 encoding and openssl does pkcs#3.
2N/A */
2N/A retval = pkinit_encode_dh_params(cryptoctx->dh->p, cryptoctx->dh->g,
2N/A cryptoctx->dh->q, dh_params, dh_params_len);
2N/A if (retval)
2N/A goto cleanup;
2N/A
2N/A /* pack DH public key */
2N/A /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2N/A * encoding shall be used as the contents (the value) of the
2N/A * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2N/A * data element
2N/A */
2N/A if ((pub_key = BN_to_ASN1_INTEGER(cryptoctx->dh->pub_key, NULL)) == NULL)
2N/A goto cleanup;
2N/A *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
2N/A if ((buf = *dh_pubkey = (unsigned char *)
2N/A malloc((size_t) *dh_pubkey_len)) == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A i2d_ASN1_INTEGER(pub_key, &buf);
2N/A
2N/A if (pub_key != NULL)
2N/A ASN1_INTEGER_free(pub_key);
2N/A
2N/A retval = 0;
2N/A return retval;
2N/A
2N/A cleanup:
2N/A if (cryptoctx->dh != NULL)
2N/A DH_free(cryptoctx->dh);
2N/A cryptoctx->dh = NULL;
2N/A if (*dh_params != NULL)
2N/A free(*dh_params);
2N/A *dh_params = NULL;
2N/A if (*dh_pubkey != NULL)
2N/A free(*dh_pubkey);
2N/A *dh_pubkey = NULL;
2N/A if (pub_key != NULL)
2N/A ASN1_INTEGER_free(pub_key);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Aclient_process_dh(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *subjectPublicKey_data,
2N/A unsigned int subjectPublicKey_length,
2N/A unsigned char **client_key,
2N/A unsigned int *client_key_len)
2N/A{
2N/A /* Solaris Kerberos */
2N/A krb5_error_code retval = KRB5_PREAUTH_FAILED;
2N/A BIGNUM *server_pub_key = NULL;
2N/A ASN1_INTEGER *pub_key = NULL;
2N/A const unsigned char *p = NULL;
2N/A unsigned char *data = NULL;
2N/A long data_len;
2N/A
2N/A /* decode subjectPublicKey (retrieve INTEGER from OCTET_STRING) */
2N/A
2N/A if (der_decode_data(subjectPublicKey_data, (long)subjectPublicKey_length,
2N/A &data, &data_len) != 0) {
2N/A pkiDebug("failed to decode subjectPublicKey\n");
2N/A /* Solaris Kerberos */
2N/A retval = KRB5_PREAUTH_FAILED;
2N/A goto cleanup;
2N/A }
2N/A
2N/A *client_key_len = DH_size(cryptoctx->dh);
2N/A if ((*client_key = (unsigned char *)
2N/A malloc((size_t) *client_key_len)) == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A p = data;
2N/A if ((pub_key = d2i_ASN1_INTEGER(NULL, &p, data_len)) == NULL)
2N/A goto cleanup;
2N/A if ((server_pub_key = ASN1_INTEGER_to_BN(pub_key, NULL)) == NULL)
2N/A goto cleanup;
2N/A
2N/A DH_compute_key(*client_key, server_pub_key, cryptoctx->dh);
2N/A#ifdef DEBUG_DH
2N/A print_pubkey(server_pub_key, "server's pub_key=");
2N/A pkiDebug("client secret key (%d)= ", *client_key_len);
2N/A print_buffer(*client_key, *client_key_len);
2N/A#endif
2N/A
2N/A retval = 0;
2N/A if (server_pub_key != NULL)
2N/A BN_free(server_pub_key);
2N/A if (pub_key != NULL)
2N/A ASN1_INTEGER_free(pub_key);
2N/A if (data != NULL)
2N/A free (data);
2N/A
2N/A return retval;
2N/A
2N/A cleanup:
2N/A if (*client_key != NULL)
2N/A free(*client_key);
2N/A *client_key = NULL;
2N/A if (pub_key != NULL)
2N/A ASN1_INTEGER_free(pub_key);
2N/A if (data != NULL)
2N/A free (data);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Aserver_check_dh(krb5_context context,
2N/A pkinit_plg_crypto_context cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_octet_data *dh_params,
2N/A int minbits)
2N/A{
2N/A DH *dh = NULL;
2N/A unsigned char *tmp = NULL;
2N/A int dh_prime_bits;
2N/A krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2N/A
2N/A tmp = dh_params->data;
2N/A dh = DH_new();
2N/A dh = pkinit_decode_dh_params(&dh, &tmp, dh_params->length);
2N/A if (dh == NULL) {
2N/A pkiDebug("failed to decode dhparams\n");
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* KDC SHOULD check to see if the key parameters satisfy its policy */
2N/A dh_prime_bits = BN_num_bits(dh->p);
2N/A if (minbits && dh_prime_bits < minbits) {
2N/A pkiDebug("client sent dh params with %d bits, we require %d\n",
2N/A dh_prime_bits, minbits);
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* check dhparams is group 2 */
2N/A if (pkinit_check_dh_params(cryptoctx->dh_1024->p,
2N/A dh->p, dh->g, dh->q) == 0) {
2N/A retval = 0;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* check dhparams is group 14 */
2N/A if (pkinit_check_dh_params(cryptoctx->dh_2048->p,
2N/A dh->p, dh->g, dh->q) == 0) {
2N/A retval = 0;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* check dhparams is group 16 */
2N/A if (pkinit_check_dh_params(cryptoctx->dh_4096->p,
2N/A dh->p, dh->g, dh->q) == 0) {
2N/A retval = 0;
2N/A goto cleanup;
2N/A }
2N/A
2N/A cleanup:
2N/A if (retval == 0)
2N/A req_cryptoctx->dh = dh;
2N/A else
2N/A DH_free(dh);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* kdc's dh function */
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Aserver_process_dh(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *data,
2N/A unsigned int data_len,
2N/A unsigned char **dh_pubkey,
2N/A unsigned int *dh_pubkey_len,
2N/A unsigned char **server_key,
2N/A unsigned int *server_key_len)
2N/A{
2N/A /* Solaris Kerberos */
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A DH *dh = NULL, *dh_server = NULL;
2N/A unsigned char *p = NULL;
2N/A ASN1_INTEGER *pub_key = NULL;
2N/A
2N/A /* get client's received DH parameters that we saved in server_check_dh */
2N/A dh = cryptoctx->dh;
2N/A
2N/A dh_server = DH_new();
2N/A if (dh_server == NULL)
2N/A goto cleanup;
2N/A dh_server->p = BN_dup(dh->p);
2N/A dh_server->g = BN_dup(dh->g);
2N/A dh_server->q = BN_dup(dh->q);
2N/A
2N/A /* decode client's public key */
2N/A p = data;
2N/A pub_key = d2i_ASN1_INTEGER(NULL, (const unsigned char **)&p, (int)data_len);
2N/A if (pub_key == NULL)
2N/A goto cleanup;
2N/A dh->pub_key = ASN1_INTEGER_to_BN(pub_key, NULL);
2N/A if (dh->pub_key == NULL)
2N/A goto cleanup;
2N/A ASN1_INTEGER_free(pub_key);
2N/A
2N/A if (!DH_generate_key(dh_server))
2N/A goto cleanup;
2N/A
2N/A /* generate DH session key */
2N/A *server_key_len = DH_size(dh_server);
2N/A if ((*server_key = (unsigned char *) malloc((size_t)*server_key_len)) == NULL)
2N/A goto cleanup;
2N/A DH_compute_key(*server_key, dh->pub_key, dh_server);
2N/A
2N/A#ifdef DEBUG_DH
2N/A print_dh(dh_server, "client&server's DH params\n");
2N/A print_pubkey(dh->pub_key, "client's pub_key=");
2N/A print_pubkey(dh_server->pub_key, "server's pub_key=");
2N/A pkiDebug("server secret key=");
2N/A print_buffer(*server_key, *server_key_len);
2N/A#endif
2N/A
2N/A /* KDC reply */
2N/A /* pack DH public key */
2N/A /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2N/A * encoding shall be used as the contents (the value) of the
2N/A * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2N/A * data element
2N/A */
2N/A if ((pub_key = BN_to_ASN1_INTEGER(dh_server->pub_key, NULL)) == NULL)
2N/A goto cleanup;
2N/A *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
2N/A if ((p = *dh_pubkey = (unsigned char *) malloc((size_t)*dh_pubkey_len)) == NULL)
2N/A goto cleanup;
2N/A i2d_ASN1_INTEGER(pub_key, &p);
2N/A if (pub_key != NULL)
2N/A ASN1_INTEGER_free(pub_key);
2N/A
2N/A retval = 0;
2N/A
2N/A if (dh_server != NULL)
2N/A DH_free(dh_server);
2N/A return retval;
2N/A
2N/A cleanup:
2N/A if (dh_server != NULL)
2N/A DH_free(dh_server);
2N/A if (*dh_pubkey != NULL)
2N/A free(*dh_pubkey);
2N/A if (*server_key != NULL)
2N/A free(*server_key);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * Add locking around did_init to make it MT-safe.
2N/A */
2N/Astatic krb5_error_code
2N/Aopenssl_init()
2N/A{
2N/A krb5_error_code ret = 0;
2N/A static int did_init = 0;
2N/A static k5_mutex_t init_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
2N/A
2N/A ret = k5_mutex_lock(&init_mutex);
2N/A if (ret == 0) {
2N/A if (!did_init) {
2N/A /* initialize openssl routines */
2N/A CRYPTO_malloc_init();
2N/A ERR_load_crypto_strings();
2N/A OpenSSL_add_all_algorithms();
2N/A did_init++;
2N/A }
2N/A k5_mutex_unlock(&init_mutex);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Apkinit_encode_dh_params(BIGNUM *p, BIGNUM *g, BIGNUM *q,
2N/A unsigned char **buf, unsigned int *buf_len)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A int bufsize = 0, r = 0;
2N/A unsigned char *tmp = NULL;
2N/A ASN1_INTEGER *ap = NULL, *ag = NULL, *aq = NULL;
2N/A
2N/A if ((ap = BN_to_ASN1_INTEGER(p, NULL)) == NULL)
2N/A goto cleanup;
2N/A if ((ag = BN_to_ASN1_INTEGER(g, NULL)) == NULL)
2N/A goto cleanup;
2N/A if ((aq = BN_to_ASN1_INTEGER(q, NULL)) == NULL)
2N/A goto cleanup;
2N/A bufsize = i2d_ASN1_INTEGER(ap, NULL);
2N/A bufsize += i2d_ASN1_INTEGER(ag, NULL);
2N/A bufsize += i2d_ASN1_INTEGER(aq, NULL);
2N/A
2N/A r = ASN1_object_size(1, bufsize, V_ASN1_SEQUENCE);
2N/A
2N/A tmp = *buf = (unsigned char *)malloc((size_t) r);
2N/A if (tmp == NULL)
2N/A goto cleanup;
2N/A
2N/A ASN1_put_object(&tmp, 1, bufsize, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2N/A
2N/A i2d_ASN1_INTEGER(ap, &tmp);
2N/A i2d_ASN1_INTEGER(ag, &tmp);
2N/A i2d_ASN1_INTEGER(aq, &tmp);
2N/A
2N/A *buf_len = r;
2N/A
2N/A retval = 0;
2N/A
2N/Acleanup:
2N/A if (ap != NULL)
2N/A ASN1_INTEGER_free(ap);
2N/A if (ag != NULL)
2N/A ASN1_INTEGER_free(ag);
2N/A if (aq != NULL)
2N/A ASN1_INTEGER_free(aq);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Astatic DH *
2N/Apkinit_decode_dh_params(DH ** a, unsigned char **pp, unsigned int len)
2N/A{
2N/A ASN1_INTEGER ai, *aip = NULL;
2N/A long length = (long) len;
2N/A
2N/A M_ASN1_D2I_vars(a, DH *, DH_new);
2N/A
2N/A M_ASN1_D2I_Init();
2N/A M_ASN1_D2I_start_sequence();
2N/A aip = &ai;
2N/A ai.data = NULL;
2N/A ai.length = 0;
2N/A M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2N/A if (aip == NULL)
2N/A return NULL;
2N/A else {
2N/A (*a)->p = ASN1_INTEGER_to_BN(aip, NULL);
2N/A if ((*a)->p == NULL)
2N/A return NULL;
2N/A if (ai.data != NULL) {
2N/A OPENSSL_free(ai.data);
2N/A ai.data = NULL;
2N/A ai.length = 0;
2N/A }
2N/A }
2N/A M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2N/A if (aip == NULL)
2N/A return NULL;
2N/A else {
2N/A (*a)->g = ASN1_INTEGER_to_BN(aip, NULL);
2N/A if ((*a)->g == NULL)
2N/A return NULL;
2N/A if (ai.data != NULL) {
2N/A OPENSSL_free(ai.data);
2N/A ai.data = NULL;
2N/A ai.length = 0;
2N/A }
2N/A
2N/A }
2N/A M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2N/A if (aip == NULL)
2N/A return NULL;
2N/A else {
2N/A (*a)->q = ASN1_INTEGER_to_BN(aip, NULL);
2N/A if ((*a)->q == NULL)
2N/A return NULL;
2N/A if (ai.data != NULL) {
2N/A OPENSSL_free(ai.data);
2N/A ai.data = NULL;
2N/A ai.length = 0;
2N/A }
2N/A
2N/A }
2N/A M_ASN1_D2I_end_sequence();
2N/A M_ASN1_D2I_Finish(a, DH_free, 0);
2N/A
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Apkinit_create_sequence_of_principal_identifiers(
2N/A krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A int type,
2N/A krb5_data **out_data)
2N/A{
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
2N/A krb5_data *td_certifiers = NULL, *data = NULL;
2N/A krb5_typed_data **typed_data = NULL;
2N/A
2N/A switch(type) {
2N/A case TD_TRUSTED_CERTIFIERS:
2N/A retval = create_krb5_trustedCertifiers(context, plg_cryptoctx,
2N/A req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2N/A if (retval) {
2N/A pkiDebug("create_krb5_trustedCertifiers failed\n");
2N/A goto cleanup;
2N/A }
2N/A break;
2N/A case TD_INVALID_CERTIFICATES:
2N/A retval = create_krb5_invalidCertificates(context, plg_cryptoctx,
2N/A req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2N/A if (retval) {
2N/A pkiDebug("create_krb5_invalidCertificates failed\n");
2N/A goto cleanup;
2N/A }
2N/A break;
2N/A default:
2N/A retval = -1;
2N/A goto cleanup;
2N/A }
2N/A
2N/A retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_trusted_certifiers, &td_certifiers);
2N/A if (retval) {
2N/A pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
2N/A goto cleanup;
2N/A }
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin((unsigned char *)td_certifiers->data,
2N/A td_certifiers->length, "/tmp/kdc_td_certifiers");
2N/A#endif
2N/A typed_data = malloc (2 * sizeof(krb5_typed_data *));
2N/A if (typed_data == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A typed_data[1] = NULL;
2N/A init_krb5_typed_data(&typed_data[0]);
2N/A if (typed_data[0] == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A typed_data[0]->type = type;
2N/A typed_data[0]->length = td_certifiers->length;
2N/A typed_data[0]->data = (unsigned char *)td_certifiers->data;
2N/A retval = k5int_encode_krb5_typed_data((const krb5_typed_data **)typed_data,
2N/A &data);
2N/A if (retval) {
2N/A pkiDebug("encode_krb5_typed_data failed\n");
2N/A goto cleanup;
2N/A }
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin((unsigned char *)data->data, data->length,
2N/A "/tmp/kdc_edata");
2N/A#endif
2N/A *out_data = (krb5_data *)malloc(sizeof(krb5_data));
2N/A (*out_data)->length = data->length;
2N/A (*out_data)->data = (char *)malloc(data->length);
2N/A (void) memcpy((*out_data)->data, data->data, data->length);
2N/A
2N/A retval = 0;
2N/A
2N/Acleanup:
2N/A if (krb5_trusted_certifiers != NULL)
2N/A free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
2N/A
2N/A if (data != NULL) {
2N/A if (data->data != NULL)
2N/A free(data->data);
2N/A free(data);
2N/A }
2N/A
2N/A if (td_certifiers != NULL)
2N/A free(td_certifiers);
2N/A
2N/A if (typed_data != NULL)
2N/A free_krb5_typed_data(&typed_data);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Apkinit_create_td_trusted_certifiers(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_data **out_data)
2N/A{
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A
2N/A retval = pkinit_create_sequence_of_principal_identifiers(context,
2N/A plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2N/A TD_TRUSTED_CERTIFIERS, out_data);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Apkinit_create_td_invalid_certificate(
2N/A krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_data **out_data)
2N/A{
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A
2N/A retval = pkinit_create_sequence_of_principal_identifiers(context,
2N/A plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2N/A TD_INVALID_CERTIFICATES, out_data);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Apkinit_create_td_dh_parameters(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A pkinit_plg_opts *opts,
2N/A krb5_data **out_data)
2N/A{
2N/A /* Solaris Kerberos */
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A unsigned int buf1_len = 0, buf2_len = 0, buf3_len = 0, i = 0;
2N/A unsigned char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
2N/A krb5_typed_data **typed_data = NULL;
2N/A krb5_data *data = NULL, *encoded_algId = NULL;
2N/A krb5_algorithm_identifier **algId = NULL;
2N/A
2N/A /* Solaris Kerberos */
2N/A if (opts->dh_min_bits > 4096) {
2N/A retval = EINVAL;
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (opts->dh_min_bits <= 1024) {
2N/A retval = pkinit_encode_dh_params(plg_cryptoctx->dh_1024->p,
2N/A plg_cryptoctx->dh_1024->g, plg_cryptoctx->dh_1024->q,
2N/A &buf1, &buf1_len);
2N/A if (retval)
2N/A goto cleanup;
2N/A }
2N/A if (opts->dh_min_bits <= 2048) {
2N/A retval = pkinit_encode_dh_params(plg_cryptoctx->dh_2048->p,
2N/A plg_cryptoctx->dh_2048->g, plg_cryptoctx->dh_2048->q,
2N/A &buf2, &buf2_len);
2N/A if (retval)
2N/A goto cleanup;
2N/A }
2N/A retval = pkinit_encode_dh_params(plg_cryptoctx->dh_4096->p,
2N/A plg_cryptoctx->dh_4096->g, plg_cryptoctx->dh_4096->q,
2N/A &buf3, &buf3_len);
2N/A if (retval)
2N/A goto cleanup;
2N/A
2N/A if (opts->dh_min_bits <= 1024) {
2N/A algId = malloc(4 * sizeof(krb5_algorithm_identifier *));
2N/A if (algId == NULL)
2N/A goto cleanup;
2N/A algId[3] = NULL;
2N/A algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2N/A if (algId[0] == NULL)
2N/A goto cleanup;
2N/A algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
2N/A if (algId[0]->parameters.data == NULL)
2N/A goto cleanup;
2N/A (void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
2N/A algId[0]->parameters.length = buf2_len;
2N/A algId[0]->algorithm = dh_oid;
2N/A
2N/A algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2N/A if (algId[1] == NULL)
2N/A goto cleanup;
2N/A algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
2N/A if (algId[1]->parameters.data == NULL)
2N/A goto cleanup;
2N/A (void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
2N/A algId[1]->parameters.length = buf3_len;
2N/A algId[1]->algorithm = dh_oid;
2N/A
2N/A algId[2] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2N/A if (algId[2] == NULL)
2N/A goto cleanup;
2N/A algId[2]->parameters.data = (unsigned char *)malloc(buf1_len);
2N/A if (algId[2]->parameters.data == NULL)
2N/A goto cleanup;
2N/A (void) memcpy(algId[2]->parameters.data, buf1, buf1_len);
2N/A algId[2]->parameters.length = buf1_len;
2N/A algId[2]->algorithm = dh_oid;
2N/A
2N/A } else if (opts->dh_min_bits <= 2048) {
2N/A algId = malloc(3 * sizeof(krb5_algorithm_identifier *));
2N/A if (algId == NULL)
2N/A goto cleanup;
2N/A algId[2] = NULL;
2N/A algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2N/A if (algId[0] == NULL)
2N/A goto cleanup;
2N/A algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
2N/A if (algId[0]->parameters.data == NULL)
2N/A goto cleanup;
2N/A (void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
2N/A algId[0]->parameters.length = buf2_len;
2N/A algId[0]->algorithm = dh_oid;
2N/A
2N/A algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2N/A if (algId[1] == NULL)
2N/A goto cleanup;
2N/A algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
2N/A if (algId[1]->parameters.data == NULL)
2N/A goto cleanup;
2N/A (void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
2N/A algId[1]->parameters.length = buf3_len;
2N/A algId[1]->algorithm = dh_oid;
2N/A
2N/A } else if (opts->dh_min_bits <= 4096) {
2N/A algId = malloc(2 * sizeof(krb5_algorithm_identifier *));
2N/A if (algId == NULL)
2N/A goto cleanup;
2N/A algId[1] = NULL;
2N/A algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2N/A if (algId[0] == NULL)
2N/A goto cleanup;
2N/A algId[0]->parameters.data = (unsigned char *)malloc(buf3_len);
2N/A if (algId[0]->parameters.data == NULL)
2N/A goto cleanup;
2N/A (void) memcpy(algId[0]->parameters.data, buf3, buf3_len);
2N/A algId[0]->parameters.length = buf3_len;
2N/A algId[0]->algorithm = dh_oid;
2N/A
2N/A }
2N/A retval = k5int_encode_krb5_td_dh_parameters((const krb5_algorithm_identifier **)algId, &encoded_algId);
2N/A if (retval)
2N/A goto cleanup;
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin((unsigned char *)encoded_algId->data,
2N/A encoded_algId->length, "/tmp/kdc_td_dh_params");
2N/A#endif
2N/A typed_data = malloc (2 * sizeof(krb5_typed_data *));
2N/A if (typed_data == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A typed_data[1] = NULL;
2N/A init_krb5_typed_data(&typed_data[0]);
2N/A if (typed_data == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A typed_data[0]->type = TD_DH_PARAMETERS;
2N/A typed_data[0]->length = encoded_algId->length;
2N/A typed_data[0]->data = (unsigned char *)encoded_algId->data;
2N/A retval = k5int_encode_krb5_typed_data((const krb5_typed_data**)typed_data,
2N/A &data);
2N/A if (retval) {
2N/A pkiDebug("encode_krb5_typed_data failed\n");
2N/A goto cleanup;
2N/A }
2N/A#ifdef DEBUG_ASN1
2N/A print_buffer_bin((unsigned char *)data->data, data->length,
2N/A "/tmp/kdc_edata");
2N/A#endif
2N/A *out_data = (krb5_data *)malloc(sizeof(krb5_data));
2N/A if (*out_data == NULL)
2N/A goto cleanup;
2N/A (*out_data)->length = data->length;
2N/A (*out_data)->data = (char *)malloc(data->length);
2N/A if ((*out_data)->data == NULL) {
2N/A free(*out_data);
2N/A *out_data = NULL;
2N/A goto cleanup;
2N/A }
2N/A (void) memcpy((*out_data)->data, data->data, data->length);
2N/A
2N/A retval = 0;
2N/Acleanup:
2N/A
2N/A if (buf1 != NULL)
2N/A free(buf1);
2N/A if (buf2 != NULL)
2N/A free(buf2);
2N/A if (buf3 != NULL)
2N/A free(buf3);
2N/A if (data != NULL) {
2N/A if (data->data != NULL)
2N/A free(data->data);
2N/A free(data);
2N/A }
2N/A if (typed_data != NULL)
2N/A free_krb5_typed_data(&typed_data);
2N/A if (encoded_algId != NULL)
2N/A free(encoded_algId);
2N/A
2N/A if (algId != NULL) {
2N/A while(algId[i] != NULL) {
2N/A if (algId[i]->parameters.data != NULL)
2N/A free(algId[i]->parameters.data);
2N/A free(algId[i]);
2N/A i++;
2N/A }
2N/A free(algId);
2N/A }
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Apkinit_check_kdc_pkid(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *pdid_buf,
2N/A unsigned int pkid_len,
2N/A int *valid_kdcPkId)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A PKCS7_ISSUER_AND_SERIAL *is = NULL;
2N/A const unsigned char *p = pdid_buf;
2N/A int status = 1;
2N/A X509 *kdc_cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
2N/A
2N/A *valid_kdcPkId = 0;
2N/A pkiDebug("found kdcPkId in AS REQ\n");
2N/A is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p, (int)pkid_len);
2N/A if (is == NULL)
2N/A goto cleanup;
2N/A
2N/A status = X509_NAME_cmp(X509_get_issuer_name(kdc_cert), is->issuer);
2N/A if (!status) {
2N/A status = ASN1_INTEGER_cmp(X509_get_serialNumber(kdc_cert), is->serial);
2N/A if (!status)
2N/A *valid_kdcPkId = 1;
2N/A }
2N/A
2N/A retval = 0;
2N/Acleanup:
2N/A X509_NAME_free(is->issuer);
2N/A ASN1_INTEGER_free(is->serial);
2N/A free(is);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Astatic int
2N/Apkinit_check_dh_params(BIGNUM * p1, BIGNUM * p2, BIGNUM * g1, BIGNUM * q1)
2N/A{
2N/A BIGNUM *g2 = NULL, *q2 = NULL;
2N/A /* Solaris Kerberos */
2N/A int retval = EINVAL;
2N/A
2N/A if (!BN_cmp(p1, p2)) {
2N/A g2 = BN_new();
2N/A BN_set_word(g2, DH_GENERATOR_2);
2N/A if (!BN_cmp(g1, g2)) {
2N/A q2 = BN_new();
2N/A BN_rshift1(q2, p1);
2N/A if (!BN_cmp(q1, q2)) {
2N/A pkiDebug("good %d dhparams\n", BN_num_bits(p1));
2N/A retval = 0;
2N/A } else
2N/A pkiDebug("bad group 2 q dhparameter\n");
2N/A BN_free(q2);
2N/A } else
2N/A pkiDebug("bad g dhparameter\n");
2N/A BN_free(g2);
2N/A } else
2N/A pkiDebug("p is not well-known group 2 dhparameter\n");
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Apkinit_process_td_dh_params(krb5_context context,
2N/A pkinit_plg_crypto_context cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_algorithm_identifier **algId,
2N/A int *new_dh_size)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2N/A int i = 0, use_sent_dh = 0, ok = 0;
2N/A
2N/A pkiDebug("dh parameters\n");
2N/A
2N/A while (algId[i] != NULL) {
2N/A DH *dh = NULL;
2N/A unsigned char *tmp = NULL;
2N/A int dh_prime_bits = 0;
2N/A
2N/A if (algId[i]->algorithm.length != dh_oid.length ||
2N/A memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
2N/A goto cleanup;
2N/A
2N/A tmp = algId[i]->parameters.data;
2N/A dh = DH_new();
2N/A dh = pkinit_decode_dh_params(&dh, &tmp, algId[i]->parameters.length);
2N/A /* Solaris Kerberos */
2N/A if (dh == NULL)
2N/A goto cleanup;
2N/A dh_prime_bits = BN_num_bits(dh->p);
2N/A pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
2N/A *new_dh_size, dh_prime_bits);
2N/A switch(dh_prime_bits) {
2N/A case 1024:
2N/A if (pkinit_check_dh_params(cryptoctx->dh_1024->p, dh->p,
2N/A dh->g, dh->q) == 0) {
2N/A *new_dh_size = 1024;
2N/A ok = 1;
2N/A }
2N/A break;
2N/A case 2048:
2N/A if (pkinit_check_dh_params(cryptoctx->dh_2048->p, dh->p,
2N/A dh->g, dh->q) == 0) {
2N/A *new_dh_size = 2048;
2N/A ok = 1;
2N/A }
2N/A break;
2N/A case 4096:
2N/A if (pkinit_check_dh_params(cryptoctx->dh_4096->p, dh->p,
2N/A dh->g, dh->q) == 0) {
2N/A *new_dh_size = 4096;
2N/A ok = 1;
2N/A }
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A if (!ok) {
2N/A DH_check(dh, &retval);
2N/A if (retval != 0) {
2N/A pkiDebug("DH parameters provided by server are unacceptable\n");
2N/A retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2N/A }
2N/A else {
2N/A use_sent_dh = 1;
2N/A ok = 1;
2N/A }
2N/A }
2N/A if (!use_sent_dh)
2N/A DH_free(dh);
2N/A if (ok) {
2N/A if (req_cryptoctx->dh != NULL) {
2N/A DH_free(req_cryptoctx->dh);
2N/A req_cryptoctx->dh = NULL;
2N/A }
2N/A if (use_sent_dh)
2N/A req_cryptoctx->dh = dh;
2N/A break;
2N/A }
2N/A i++;
2N/A }
2N/A
2N/A if (ok)
2N/A retval = 0;
2N/A
2N/Acleanup:
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic int
2N/Aopenssl_callback(int ok, X509_STORE_CTX * ctx)
2N/A{
2N/A#ifdef DEBUG
2N/A if (!ok) {
2N/A char buf[DN_BUF_LEN];
2N/A
2N/A X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf));
2N/A pkiDebug("cert = %s\n", buf);
2N/A pkiDebug("callback function: %d (%s)\n", ctx->error,
2N/A X509_verify_cert_error_string(ctx->error));
2N/A }
2N/A#endif
2N/A return ok;
2N/A}
2N/A
2N/Astatic int
2N/Aopenssl_callback_ignore_crls(int ok, X509_STORE_CTX * ctx)
2N/A{
2N/A if (!ok) {
2N/A switch (ctx->error) {
2N/A case X509_V_ERR_UNABLE_TO_GET_CRL:
2N/A return 1;
2N/A default:
2N/A return 0;
2N/A }
2N/A }
2N/A return ok;
2N/A}
2N/A
2N/Astatic ASN1_OBJECT *
2N/Apkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
2N/A{
2N/A int nid;
2N/A
2N/A switch (pkcs7_type) {
2N/A case CMS_SIGN_CLIENT:
2N/A return cryptoctx->id_pkinit_authData;
2N/A case CMS_SIGN_DRAFT9:
2N/A /*
2N/A * Delay creating this OID until we know we need it.
2N/A * It shadows an existing OpenSSL oid. If it
2N/A * is created too early, it breaks things like
2N/A * the use of pkcs12 (which uses pkcs7 structures).
2N/A * We need this shadow version because our code
2N/A * depends on the "other" type to be unknown to the
2N/A * OpenSSL code.
2N/A */
2N/A if (cryptoctx->id_pkinit_authData9 == NULL) {
2N/A pkiDebug("%s: Creating shadow instance of pkcs7-data oid\n",
2N/A __FUNCTION__);
2N/A nid = OBJ_create("1.2.840.113549.1.7.1", "id-pkcs7-data",
2N/A "PKCS7 data");
2N/A if (nid == NID_undef)
2N/A return NULL;
2N/A cryptoctx->id_pkinit_authData9 = OBJ_nid2obj(nid);
2N/A }
2N/A return cryptoctx->id_pkinit_authData9;
2N/A case CMS_SIGN_SERVER:
2N/A return cryptoctx->id_pkinit_DHKeyData;
2N/A case CMS_ENVEL_SERVER:
2N/A return cryptoctx->id_pkinit_rkeyData;
2N/A default:
2N/A return NULL;
2N/A }
2N/A
2N/A}
2N/A
2N/A#ifdef LONGHORN_BETA_COMPAT
2N/A#if 0
2N/A/*
2N/A * This is a version that worked with Longhorn Beta 3.
2N/A */
2N/Astatic int
2N/Awrap_signeddata(unsigned char *data, unsigned int data_len,
2N/A unsigned char **out, unsigned int *out_len,
2N/A int is_longhorn_server)
2N/A{
2N/A
2N/A unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
2N/A ASN1_OBJECT *oid = NULL;
2N/A unsigned char *p = NULL;
2N/A
2N/A pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
2N/A __FUNCTION__, is_longhorn_server);
2N/A
2N/A /* Get length to wrap the original data with SEQUENCE tag */
2N/A tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
2N/A
2N/A if (is_longhorn_server == 0) {
2N/A /* Add the signedData OID and adjust lengths */
2N/A oid = OBJ_nid2obj(NID_pkcs7_signed);
2N/A oid_len = i2d_ASN1_OBJECT(oid, NULL);
2N/A
2N/A tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
2N/A }
2N/A
2N/A p = *out = (unsigned char *)malloc(tot_len);
2N/A if (p == NULL) return -1;
2N/A
2N/A if (is_longhorn_server == 0) {
2N/A ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
2N/A V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2N/A
2N/A i2d_ASN1_OBJECT(oid, &p);
2N/A
2N/A ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
2N/A } else {
2N/A ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2N/A }
2N/A memcpy(p, data, data_len);
2N/A
2N/A *out_len = tot_len;
2N/A
2N/A return 0;
2N/A}
2N/A#else
2N/A/*
2N/A * This is a version that works with a patched Longhorn KDC.
2N/A * (Which should match SP1 ??).
2N/A */
2N/Astatic int
2N/Awrap_signeddata(unsigned char *data, unsigned int data_len,
2N/A unsigned char **out, unsigned int *out_len,
2N/A int is_longhorn_server)
2N/A{
2N/A
2N/A unsigned int oid_len = 0, tot_len = 0, wrap_len = 0, tag_len = 0;
2N/A ASN1_OBJECT *oid = NULL;
2N/A unsigned char *p = NULL;
2N/A
2N/A pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
2N/A __FUNCTION__, is_longhorn_server);
2N/A
2N/A /* New longhorn is missing another sequence */
2N/A if (is_longhorn_server == 1)
2N/A wrap_len = ASN1_object_size(1, (int)(data_len), V_ASN1_SEQUENCE);
2N/A else
2N/A wrap_len = data_len;
2N/A
2N/A /* Get length to wrap the original data with SEQUENCE tag */
2N/A tag_len = ASN1_object_size(1, (int)wrap_len, V_ASN1_SEQUENCE);
2N/A
2N/A /* Always add oid */
2N/A oid = OBJ_nid2obj(NID_pkcs7_signed);
2N/A oid_len = i2d_ASN1_OBJECT(oid, NULL);
2N/A oid_len += tag_len;
2N/A
2N/A tot_len = ASN1_object_size(1, (int)(oid_len), V_ASN1_SEQUENCE);
2N/A
2N/A p = *out = (unsigned char *)malloc(tot_len);
2N/A if (p == NULL)
2N/A return -1;
2N/A
2N/A ASN1_put_object(&p, 1, (int)(oid_len),
2N/A V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2N/A
2N/A i2d_ASN1_OBJECT(oid, &p);
2N/A
2N/A ASN1_put_object(&p, 1, (int)wrap_len, 0, V_ASN1_CONTEXT_SPECIFIC);
2N/A
2N/A /* Wrap in extra seq tag */
2N/A if (is_longhorn_server == 1) {
2N/A ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2N/A }
2N/A (void) memcpy(p, data, data_len);
2N/A
2N/A *out_len = tot_len;
2N/A
2N/A return 0;
2N/A}
2N/A
2N/A#endif
2N/A#else
2N/Astatic int
2N/Awrap_signeddata(unsigned char *data, unsigned int data_len,
2N/A unsigned char **out, unsigned int *out_len)
2N/A{
2N/A
2N/A unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
2N/A ASN1_OBJECT *oid = NULL;
2N/A unsigned char *p = NULL;
2N/A
2N/A /* Get length to wrap the original data with SEQUENCE tag */
2N/A tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
2N/A
2N/A /* Add the signedData OID and adjust lengths */
2N/A oid = OBJ_nid2obj(NID_pkcs7_signed);
2N/A oid_len = i2d_ASN1_OBJECT(oid, NULL);
2N/A
2N/A tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
2N/A
2N/A p = *out = (unsigned char *)malloc(tot_len);
2N/A if (p == NULL) return -1;
2N/A
2N/A ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
2N/A V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2N/A
2N/A i2d_ASN1_OBJECT(oid, &p);
2N/A
2N/A ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
2N/A (void) memcpy(p, data, data_len);
2N/A
2N/A *out_len = tot_len;
2N/A
2N/A return 0;
2N/A}
2N/A#endif
2N/A
2N/Astatic int
2N/Aprepare_enc_data(unsigned char *indata,
2N/A int indata_len,
2N/A unsigned char **outdata,
2N/A int *outdata_len)
2N/A{
2N/A /* Solaris Kerberos */
2N/A ASN1_const_CTX c;
2N/A long length = indata_len;
2N/A int Ttag, Tclass;
2N/A long Tlen;
2N/A
2N/A c.pp = (const unsigned char **)&indata;
2N/A c.q = *(const unsigned char **)&indata;
2N/A c.error = ERR_R_NESTED_ASN1_ERROR;
2N/A c.p= *(const unsigned char **)&indata;
2N/A c.max = (length == 0)?0:(c.p+length);
2N/A
2N/A asn1_GetSequence(&c,&length);
2N/A
2N/A ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
2N/A c.p += Tlen;
2N/A ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
2N/A
2N/A asn1_const_Finish(&c);
2N/A
2N/A *outdata = (unsigned char *)malloc((size_t)Tlen);
2N/A /* Solaris Kerberos */
2N/A if (outdata == NULL)
2N/A return ENOMEM;
2N/A
2N/A (void) memcpy(*outdata, c.p, (size_t)Tlen);
2N/A *outdata_len = Tlen;
2N/A
2N/A return 0;
2N/A}
2N/A
2N/A#ifndef WITHOUT_PKCS11
2N/Astatic void *
2N/Apkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
2N/A{
2N/A void *handle;
2N/A CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
2N/A
2N/A pkiDebug("loading module \"%s\"... ", modname);
2N/A /* Solaris Kerberos */
2N/A handle = dlopen(modname, RTLD_NOW | RTLD_GROUP);
2N/A if (handle == NULL) {
2N/A pkiDebug("not found\n");
2N/A return NULL;
2N/A }
2N/A getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
2N/A if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
2N/A (void) dlclose(handle);
2N/A pkiDebug("failed\n");
2N/A return NULL;
2N/A }
2N/A pkiDebug("ok\n");
2N/A return handle;
2N/A}
2N/A
2N/Astatic CK_RV
2N/Apkinit_C_UnloadModule(void *handle)
2N/A{
2N/A /* Solaris Kerberos */
2N/A if (dlclose(handle) != 0)
2N/A return CKR_GENERAL_ERROR;
2N/A
2N/A return CKR_OK;
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos: this is a new function that does not exist yet in the MIT
2N/A * code.
2N/A *
2N/A * labelstr will be C string containing token label with trailing white space
2N/A * removed.
2N/A */
2N/Astatic void
2N/Atrim_token_label(CK_TOKEN_INFO *tinfo, char *labelstr, unsigned int labelstr_len)
2N/A{
2N/A int i;
2N/A
2N/A assert(labelstr_len > sizeof (tinfo->label));
2N/A /*
2N/A * \0 terminate labelstr in case the last char in the token label is
2N/A * non-whitespace
2N/A */
2N/A labelstr[sizeof (tinfo->label)] = '\0';
2N/A (void) memcpy(labelstr, (char *) tinfo->label, sizeof (tinfo->label));
2N/A
2N/A /* init i so terminating \0 is skipped */
2N/A for (i = sizeof (tinfo->label) - 1; i >= 0; i--) {
2N/A if (labelstr[i] == ' ')
2N/A labelstr[i] = '\0';
2N/A else
2N/A break;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos: this is a new function that does not exist yet in the MIT
2N/A * code.
2N/A */
2N/Astatic krb5_error_code
2N/Apkinit_prompt_user(krb5_context context,
2N/A pkinit_identity_crypto_context cctx,
2N/A krb5_data *reply,
2N/A char *prompt,
2N/A int hidden)
2N/A{
2N/A krb5_error_code r;
2N/A krb5_prompt kprompt;
2N/A krb5_prompt_type prompt_type;
2N/A
2N/A if (cctx->prompter == NULL)
2N/A return (EINVAL);
2N/A
2N/A kprompt.prompt = prompt;
2N/A kprompt.hidden = hidden;
2N/A kprompt.reply = reply;
2N/A /*
2N/A * Note, assuming this type for now, may need to be passed in in the future.
2N/A */
2N/A prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
2N/A
2N/A /* PROMPTER_INVOCATION */
2N/A k5int_set_prompt_types(context, &prompt_type);
2N/A r = (*cctx->prompter)(context, cctx->prompter_data,
2N/A NULL, NULL, 1, &kprompt);
2N/A k5int_set_prompt_types(context, NULL);
2N/A return (r);
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos: this function was changed to support a PIN being passed
2N/A * in. If that is the case the user will not be prompted for their PIN.
2N/A */
2N/Astatic krb5_error_code
2N/Apkinit_login(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A CK_TOKEN_INFO *tip)
2N/A{
2N/A krb5_data rdat;
2N/A char *prompt;
2N/A int prompt_len;
2N/A int r = 0;
2N/A
2N/A if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
2N/A rdat.data = NULL;
2N/A rdat.length = 0;
2N/A } else if (id_cryptoctx->PIN != NULL) {
2N/A if ((rdat.data = strdup(id_cryptoctx->PIN)) == NULL)
2N/A return (ENOMEM);
2N/A /*
2N/A * Don't include NULL string terminator in length calculation as this
2N/A * PIN is passed to the C_Login function and only the text chars should
2N/A * be considered to be the PIN.
2N/A */
2N/A rdat.length = strlen(id_cryptoctx->PIN);
2N/A } else {
2N/A /* Solaris Kerberos - trim token label */
2N/A char tmplabel[sizeof (tip->label) + 1];
2N/A
2N/A if (!id_cryptoctx->prompter) {
2N/A pkiDebug("pkinit_login: id_cryptoctx->prompter is NULL\n");
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Failed to log into token: prompter function is NULL"));
2N/A return (KRB5KDC_ERR_PREAUTH_FAILED);
2N/A }
2N/A /* Solaris Kerberos - Changes for gettext() */
2N/A prompt_len = sizeof (tip->label) + 256;
2N/A if ((prompt = (char *) malloc(prompt_len)) == NULL)
2N/A return ENOMEM;
2N/A
2N/A /* Solaris Kerberos - trim token label which can be padded with space */
2N/A trim_token_label(tip, tmplabel, sizeof (tmplabel));
2N/A (void) snprintf(prompt, prompt_len, gettext("%s PIN"), tmplabel);
2N/A
2N/A /* Solaris Kerberos */
2N/A if (tip->flags & CKF_USER_PIN_LOCKED)
2N/A (void) strlcat(prompt, gettext(" (Warning: PIN locked)"), prompt_len);
2N/A else if (tip->flags & CKF_USER_PIN_FINAL_TRY)
2N/A (void) strlcat(prompt, gettext(" (Warning: PIN final try)"), prompt_len);
2N/A else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
2N/A (void) strlcat(prompt, gettext(" (Warning: PIN count low)"), prompt_len);
2N/A rdat.data = malloc(tip->ulMaxPinLen + 2);
2N/A rdat.length = tip->ulMaxPinLen + 1;
2N/A /*
2N/A * Note that the prompter function will set rdat.length such that the
2N/A * NULL terminator is not included
2N/A */
2N/A /* PROMPTER_INVOCATION */
2N/A r = pkinit_prompt_user(context, id_cryptoctx, &rdat, prompt, 1);
2N/A free(prompt);
2N/A }
2N/A
2N/A if (r == 0) {
2N/A r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
2N/A (u_char *) rdat.data, rdat.length);
2N/A
2N/A if (r != CKR_OK) {
2N/A pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Failed to log into token: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A } else {
2N/A /* Solaris Kerberos: only need to login once */
2N/A id_cryptoctx->p11flags |= C_LOGIN_DONE;
2N/A }
2N/A }
2N/A if (rdat.data) {
2N/A (void) memset(rdat.data, 0, rdat.length);
2N/A free(rdat.data);
2N/A }
2N/A
2N/A return (r);
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos: added these structs in support of prompting user for
2N/A * missing token.
2N/A */
2N/Astruct _token_entry {
2N/A CK_SLOT_ID slotID;
2N/A CK_SESSION_HANDLE session;
2N/A CK_TOKEN_INFO token_info;
2N/A};
2N/Astruct _token_choices {
2N/A unsigned int numtokens;
2N/A struct _token_entry *token_array;
2N/A};
2N/A
2N/A
2N/A/*
2N/A * Solaris Kerberos: this is a new function that does not exist yet in the MIT
2N/A * code.
2N/A */
2N/Astatic krb5_error_code
2N/Apkinit_prompt_token(krb5_context context,
2N/A pkinit_identity_crypto_context cctx)
2N/A{
2N/A char tmpbuf[4];
2N/A krb5_data reply;
2N/A char *token_prompt = gettext("If you have a smartcard insert it now. "
2N/A "Press enter to continue");
2N/A
2N/A reply.data = tmpbuf;
2N/A reply.length = sizeof(tmpbuf);
2N/A
2N/A /* note, don't care about the reply */
2N/A return (pkinit_prompt_user(context, cctx, &reply, token_prompt, 0));
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos: new defines for prompting support.
2N/A */
2N/A#define CHOOSE_THIS_TOKEN 0
2N/A#define CHOOSE_RESCAN 1
2N/A#define CHOOSE_SKIP 2
2N/A#define CHOOSE_SEE_NEXT 3
2N/A
2N/A#define RESCAN_TOKENS -1
2N/A#define SKIP_TOKENS -2
2N/A
2N/A/*
2N/A * Solaris Kerberos: this is a new function that does not exist yet in the MIT
2N/A * code.
2N/A *
2N/A * This prompts to user for various choices regarding a token to use. Note
2N/A * that if there is no error, choice will be set to one of:
2N/A * - the token_choices->token_array entry
2N/A * - RESCAN_TOKENS
2N/A * - SKIP_TOKENS
2N/A */
2N/Astatic int
2N/Apkinit_choose_tokens(krb5_context context,
2N/A pkinit_identity_crypto_context cctx,
2N/A struct _token_choices *token_choices,
2N/A int *choice)
2N/A{
2N/A krb5_error_code r;
2N/A /*
2N/A * Assuming that PAM_MAX_MSG_SIZE is a reasonable restriction. Note that -
2N/A * 2 is to account for the fact that a krb prompter to PAM conv bridge will
2N/A * add ": ".
2N/A */
2N/A char prompt[PAM_MAX_MSG_SIZE - 2];
2N/A char tmpbuf[4];
2N/A char tmplabel[sizeof (token_choices->token_array->token_info.label) + 1];
2N/A krb5_data reply;
2N/A int i, num_used, tmpchoice;
2N/A
2N/A assert(token_choices != NULL);
2N/A assert(choice != NULL);
2N/A
2N/A /* Create the menu prompt */
2N/A
2N/A /* only need to do this once before the for loop */
2N/A reply.data = tmpbuf;
2N/A
2N/A for (i = 0; i < token_choices->numtokens; i++) {
2N/A
2N/A trim_token_label(&token_choices->token_array[i].token_info, tmplabel,
2N/A sizeof (tmplabel));
2N/A
2N/A if (i == (token_choices->numtokens - 1)) {
2N/A /* no more smartcards/tokens */
2N/A if ((num_used = snprintf(prompt, sizeof (prompt),
2N/A "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n",
2N/A /*
2N/A * TRANSLATION_NOTE: Translations of the
2N/A * following 5 strings must not exceed 450
2N/A * bytes total.
2N/A */
2N/A gettext("Select one of the following and press enter:"),
2N/A CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
2N/A gettext("in slot"), token_choices->token_array[i].slotID,
2N/A CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
2N/A CHOOSE_SKIP, gettext("Skip smartcard authentication")))
2N/A >= sizeof (prompt)) {
2N/A pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
2N/A " sizeof prompt: %d\n", num_used, sizeof (prompt));
2N/A krb5_set_error_message(context, EINVAL,
2N/A gettext("In pkinit_choose_tokens: prompt size"
2N/A " %d exceeds prompt buffer size %d"),
2N/A num_used, sizeof(prompt));
2N/A (void) snprintf(prompt, sizeof (prompt), "%s",
2N/A gettext("Error: PKINIT prompt message is too large for buffer, "
2N/A "please alert the system administrator. Press enter to "
2N/A "continue"));
2N/A reply.length = sizeof(tmpbuf);
2N/A if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
2N/A return (r);
2N/A return (EINVAL);
2N/A }
2N/A } else {
2N/A if ((num_used = snprintf(prompt, sizeof (prompt),
2N/A "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n%d: %s\n",
2N/A /*
2N/A * TRANSLATION_NOTE: Translations of the
2N/A * following 6 strings must not exceed 445
2N/A * bytes total.
2N/A */
2N/A gettext("Select one of the following and press enter:"),
2N/A CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
2N/A gettext("in slot"), token_choices->token_array[i].slotID,
2N/A CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
2N/A CHOOSE_SKIP, gettext("Skip smartcard authentication"),
2N/A CHOOSE_SEE_NEXT, gettext("See next smartcard")))
2N/A >= sizeof (prompt)) {
2N/A
2N/A pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
2N/A " sizeof prompt: %d\n", num_used, sizeof (prompt));
2N/A krb5_set_error_message(context, EINVAL,
2N/A gettext("In pkinit_choose_tokens: prompt size"
2N/A " %d exceeds prompt buffer size %d"),
2N/A num_used, sizeof(prompt));
2N/A (void) snprintf(prompt, sizeof (prompt), "%s",
2N/A gettext("Error: PKINIT prompt message is too large for buffer, "
2N/A "please alert the system administrator. Press enter to "
2N/A "continue"));
2N/A reply.length = sizeof(tmpbuf);
2N/A if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
2N/A return (r);
2N/A return (EINVAL);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * reply.length needs to be reset to length of tmpbuf before calling
2N/A * prompter
2N/A */
2N/A reply.length = sizeof(tmpbuf);
2N/A if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
2N/A return (r);
2N/A
2N/A if (reply.length == 0) {
2N/A return (EINVAL);
2N/A } else {
2N/A char *cp = reply.data;
2N/A /* reply better be digits */
2N/A while (*cp != NULL) {
2N/A if (!isdigit(*cp++))
2N/A return (EINVAL);
2N/A }
2N/A errno = 0;
2N/A tmpchoice = (int) strtol(reply.data, (char **)NULL, 10);
2N/A if (errno != 0)
2N/A return (errno);
2N/A }
2N/A
2N/A switch (tmpchoice) {
2N/A case CHOOSE_THIS_TOKEN:
2N/A *choice = i; /* chosen entry of token_choices->token_array */
2N/A return (0);
2N/A case CHOOSE_RESCAN:
2N/A *choice = RESCAN_TOKENS; /* rescan for new smartcard */
2N/A return (0);
2N/A case CHOOSE_SKIP:
2N/A *choice = SKIP_TOKENS; /* skip smartcard auth */
2N/A return (0);
2N/A case CHOOSE_SEE_NEXT: /* see next smartcard */
2N/A continue;
2N/A default:
2N/A return (EINVAL);
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos: this is a new function that does not exist yet in the MIT
2N/A * code.
2N/A *
2N/A * Note, this isn't the best solution to providing a function to check the
2N/A * certs in a token however I wanted to avoid rewriting a bunch of code so I
2N/A * settled for some duplication of processing.
2N/A */
2N/Astatic krb5_error_code
2N/Acheck_load_certs(krb5_context context,
2N/A CK_SESSION_HANDLE session,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_principal princ,
2N/A int do_matching,
2N/A int load_cert)
2N/A{
2N/A CK_OBJECT_CLASS cls;
2N/A CK_OBJECT_HANDLE obj;
2N/A CK_ATTRIBUTE attrs[4];
2N/A CK_ULONG count;
2N/A CK_CERTIFICATE_TYPE certtype;
2N/A CK_BYTE_PTR cert = NULL, cert_id = NULL;
2N/A const unsigned char *cp;
2N/A int i, r;
2N/A unsigned int nattrs;
2N/A X509 *x = NULL;
2N/A
2N/A cls = CKO_CERTIFICATE;
2N/A attrs[0].type = CKA_CLASS;
2N/A attrs[0].pValue = &cls;
2N/A attrs[0].ulValueLen = sizeof cls;
2N/A
2N/A certtype = CKC_X_509;
2N/A attrs[1].type = CKA_CERTIFICATE_TYPE;
2N/A attrs[1].pValue = &certtype;
2N/A attrs[1].ulValueLen = sizeof certtype;
2N/A
2N/A nattrs = 2;
2N/A
2N/A /* If a cert id and/or label were given, use them too */
2N/A if (id_cryptoctx->cert_id_len > 0) {
2N/A attrs[nattrs].type = CKA_ID;
2N/A attrs[nattrs].pValue = id_cryptoctx->cert_id;
2N/A attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
2N/A nattrs++;
2N/A }
2N/A if (id_cryptoctx->cert_label != NULL) {
2N/A attrs[nattrs].type = CKA_LABEL;
2N/A attrs[nattrs].pValue = id_cryptoctx->cert_label;
2N/A attrs[nattrs].ulValueLen = strlen(id_cryptoctx->cert_label);
2N/A nattrs++;
2N/A }
2N/A
2N/A r = id_cryptoctx->p11->C_FindObjectsInit(session, attrs, nattrs);
2N/A if (r != CKR_OK) {
2N/A pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A krb5_set_error_message(context, EINVAL,
2N/A gettext("PKCS11 error from C_FindObjectsInit: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A r = EINVAL;
2N/A goto out;
2N/A }
2N/A
2N/A for (i = 0; ; i++) {
2N/A if (i >= MAX_CREDS_ALLOWED) {
2N/A r = EINVAL;
2N/A goto out;
2N/A }
2N/A
2N/A /* Look for x.509 cert */
2N/A /* Solaris Kerberos */
2N/A if ((r = id_cryptoctx->p11->C_FindObjects(session, &obj, 1, &count))
2N/A != CKR_OK || count == 0) {
2N/A id_cryptoctx->creds[i] = NULL;
2N/A break;
2N/A }
2N/A
2N/A /* Get cert and id len */
2N/A attrs[0].type = CKA_VALUE;
2N/A attrs[0].pValue = NULL;
2N/A attrs[0].ulValueLen = 0;
2N/A
2N/A attrs[1].type = CKA_ID;
2N/A attrs[1].pValue = NULL;
2N/A attrs[1].ulValueLen = 0;
2N/A
2N/A if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
2N/A obj,
2N/A attrs,
2N/A 2)) != CKR_OK &&
2N/A r != CKR_BUFFER_TOO_SMALL) {
2N/A pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A krb5_set_error_message(context, EINVAL,
2N/A gettext("Error from PKCS11 C_GetAttributeValue: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A r = EINVAL;
2N/A goto out;
2N/A }
2N/A cert = malloc((size_t) attrs[0].ulValueLen + 1);
2N/A if (cert == NULL) {
2N/A r = ENOMEM;
2N/A goto out;
2N/A }
2N/A cert_id = malloc((size_t) attrs[1].ulValueLen + 1);
2N/A if (cert_id == NULL) {
2N/A r = ENOMEM;
2N/A goto out;
2N/A }
2N/A
2N/A /* Read the cert and id off the card */
2N/A
2N/A attrs[0].type = CKA_VALUE;
2N/A attrs[0].pValue = cert;
2N/A
2N/A attrs[1].type = CKA_ID;
2N/A attrs[1].pValue = cert_id;
2N/A
2N/A if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
2N/A obj, attrs, 2)) != CKR_OK) {
2N/A pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A krb5_set_error_message(context, EINVAL,
2N/A gettext("Error from PKCS11 C_GetAttributeValue: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A r = EINVAL;
2N/A goto out;
2N/A }
2N/A
2N/A pkiDebug("cert %d size %d id %d idlen %d\n", i,
2N/A (int) attrs[0].ulValueLen, (int) cert_id[0],
2N/A (int) attrs[1].ulValueLen);
2N/A
2N/A cp = (unsigned char *) cert;
2N/A x = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
2N/A if (x == NULL) {
2N/A r = EINVAL;
2N/A goto out;
2N/A }
2N/A
2N/A id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
2N/A if (id_cryptoctx->creds[i] == NULL) {
2N/A r = ENOMEM;
2N/A goto out;
2N/A }
2N/A id_cryptoctx->creds[i]->cert = x;
2N/A id_cryptoctx->creds[i]->key = NULL;
2N/A id_cryptoctx->creds[i]->cert_id = cert_id;
2N/A cert_id = NULL;
2N/A id_cryptoctx->creds[i]->cert_id_len = attrs[1].ulValueLen;
2N/A free(cert);
2N/A cert = NULL;
2N/A }
2N/A id_cryptoctx->p11->C_FindObjectsFinal(session);
2N/A
2N/A if (id_cryptoctx->creds[0] == NULL || id_cryptoctx->creds[0]->cert == NULL) {
2N/A r = ENOENT;
2N/A } else if (do_matching){
2N/A /*
2N/A * Do not let pkinit_cert_matching set the primary cert in id_cryptoctx
2N/A * as this will be done later.
2N/A */
2N/A r = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
2N/A id_cryptoctx, princ, FALSE);
2N/A }
2N/A
2N/Aout:
2N/A if ((r != 0 || !load_cert) &&
2N/A id_cryptoctx->creds[0] != NULL &&
2N/A id_cryptoctx->creds[0]->cert != NULL) {
2N/A /*
2N/A * If there's an error or load_cert isn't 1 free all the certs loaded
2N/A * onto id_cryptoctx.
2N/A */
2N/A (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
2N/A id_cryptoctx);
2N/A }
2N/A
2N/A if (cert)
2N/A free(cert);
2N/A
2N/A if (cert_id)
2N/A free(cert_id);
2N/A
2N/A return (r);
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos: this function has been significantly modified to prompt
2N/A * the user in certain cases so defer to this version when resyncing MIT code.
2N/A *
2N/A * pkinit_open_session now does several things including prompting the user if
2N/A * do_matching is set which indicates the code is executing in a client
2N/A * context. This function fills out a pkinit_identity_crypto_context with a
2N/A * set of certs and a open session if a token can be found that matches all
2N/A * supplied criteria. If no token is found then the user is prompted one time
2N/A * to insert their token. If there is more than one token that matches all
2N/A * client criteria the user is prompted to make a choice if in client context.
2N/A * If do_matching is false (KDC context) then the first token matching all
2N/A * server criteria is chosen.
2N/A */
2N/Astatic krb5_error_code
2N/Apkinit_open_session(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context cctx,
2N/A krb5_principal princ,
2N/A int do_matching)
2N/A{
2N/A int i, r;
2N/A CK_ULONG count = 0;
2N/A CK_SLOT_ID_PTR slotlist = NULL, tmpslotlist = NULL;
2N/A CK_TOKEN_INFO tinfo;
2N/A krb5_boolean tokenmatch = FALSE;
2N/A CK_SESSION_HANDLE tmpsession = NULL;
2N/A struct _token_choices token_choices;
2N/A int choice = 0;
2N/A
2N/A if (cctx->session != CK_INVALID_HANDLE)
2N/A return 0; /* session already open */
2N/A
2N/A /* Load module */
2N/A if (cctx->p11_module == NULL) {
2N/A cctx->p11_module =
2N/A pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11);
2N/A if (cctx->p11_module == NULL)
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A
2N/A /* Init */
2N/A /* Solaris Kerberos: Don't fail if cryptoki is already initialized */
2N/A r = cctx->p11->C_Initialize(NULL);
2N/A if (r != CKR_OK && r != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
2N/A pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Error from PKCS11 C_Initialize: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A
2N/A (void) memset(&token_choices, 0, sizeof(token_choices));
2N/A
2N/A /*
2N/A * Solaris Kerberos:
2N/A * If C_Initialize was already called by the process before the pkinit
2N/A * module was loaded then record that fact.
2N/A * "finalize_pkcs11" is used by pkinit_fini_pkcs11 to determine whether
2N/A * or not C_Finalize() should be called.
2N/A */
2N/A cctx->finalize_pkcs11 =
2N/A (r == CKR_CRYPTOKI_ALREADY_INITIALIZED ? FALSE : TRUE);
2N/A /*
2N/A * First make sure that is an applicable slot otherwise fail.
2N/A *
2N/A * Start by getting a count of all slots with or without tokens.
2N/A */
2N/A
2N/A if ((r = cctx->p11->C_GetSlotList(FALSE, NULL, &count)) != CKR_OK) {
2N/A pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Error trying to get PKCS11 slot list: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A
2N/A if (count == 0) {
2N/A /* There are no slots so bail */
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, r,
2N/A gettext("No PKCS11 slots found"));
2N/A pkiDebug("pkinit_open_session: no slots, count: %d\n", count);
2N/A goto out;
2N/A } else if (cctx->slotid != PK_NOSLOT) {
2N/A /* See if any of the slots match the specified slotID */
2N/A tmpslotlist = malloc(count * sizeof (CK_SLOT_ID));
2N/A if (tmpslotlist == NULL) {
2N/A krb5_set_error_message(context, ENOMEM,
2N/A gettext("Memory allocation error:"));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A if ((r = cctx->p11->C_GetSlotList(FALSE, tmpslotlist, &count)) != CKR_OK) {
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Error trying to get PKCS11 slot list: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A
2N/A for (i = 0; i < count && cctx->slotid != tmpslotlist[i]; i++)
2N/A continue;
2N/A
2N/A if (i >= count) {
2N/A /* no slots match */
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, r,
2N/A gettext("Requested PKCS11 slot ID %d not found"),
2N/A cctx->slotid);
2N/A pkiDebug("open_session: no matching slot found for slotID %d\n",
2N/A cctx->slotid);
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/Atryagain:
2N/A /* get count of slots that have tokens */
2N/A if ((r = cctx->p11->C_GetSlotList(TRUE, NULL, &count)) != CKR_OK) {
2N/A pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Error trying to get PKCS11 slot list: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A
2N/A if (count == 0) {
2N/A /*
2N/A * Note, never prompt if !do_matching as this implies KDC side
2N/A * processing
2N/A */
2N/A if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
2N/A /* found slot(s) but no token so prompt and try again */
2N/A if ((r = pkinit_prompt_token(context, cctx)) == 0) {
2N/A cctx->p11flags |= C_PROMPTED_USER;
2N/A goto tryagain;
2N/A } else {
2N/A pkiDebug("open_session: prompt for token/smart card failed\n");
2N/A krb5_set_error_message(context, r,
2N/A gettext("Prompt for token/smart card failed"));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A
2N/A } else {
2N/A /* already prompted once so bailing */
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, r,
2N/A gettext("No smart card tokens found"));
2N/A pkiDebug("pkinit_open_session: no token, already prompted\n");
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A if (slotlist != NULL)
2N/A free(slotlist);
2N/A
2N/A slotlist = malloc(count * sizeof (CK_SLOT_ID));
2N/A if (slotlist == NULL) {
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Memory allocation error"));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A /*
2N/A * Solaris Kerberos: get list of PKCS11 slotid's that have tokens.
2N/A */
2N/A if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Error trying to get PKCS11 slot list: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A
2N/A token_choices.numtokens = 0;
2N/A token_choices.token_array = malloc(count * sizeof (*token_choices.token_array));
2N/A if (token_choices.token_array == NULL) {
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, r,
2N/A gettext("Memory allocation error"));
2N/A goto out;
2N/A }
2N/A
2N/A /* examine all the tokens */
2N/A for (i = 0; i < count; i++) {
2N/A /*
2N/A * Solaris Kerberos: if a slotid was specified skip slots that don't
2N/A * match.
2N/A */
2N/A if (cctx->slotid != PK_NOSLOT && cctx->slotid != slotlist[i])
2N/A continue;
2N/A
2N/A /* Open session */
2N/A if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
2N/A NULL, NULL, &tmpsession)) != CKR_OK) {
2N/A pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Error trying to open PKCS11 session: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A
2N/A /* Get token info */
2N/A if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) {
2N/A pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
2N/A gettext("Error trying to read PKCS11 token: %s"),
2N/A pkinit_pkcs11_code_to_text(r));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A cctx->p11->C_CloseSession(tmpsession);
2N/A goto out;
2N/A }
2N/A
2N/A if (cctx->token_label == NULL) {
2N/A /*
2N/A * If the token doesn't require login to examine the certs then
2N/A * let's check the certs out to see if any match the criteria if
2N/A * any.
2N/A */
2N/A if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
2N/A /*
2N/A * It's okay to check the certs if we don't have to login but
2N/A * don't load the certs onto cctx at this point, this will be
2N/A * done later in this function for the chosen token.
2N/A */
2N/A if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
2N/A req_cryptoctx, cctx, princ,
2N/A do_matching, 0)) == 0) {
2N/A tokenmatch = TRUE;
2N/A } else if (r != ENOENT){
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A cctx->p11->C_CloseSession(tmpsession);
2N/A goto out;
2N/A } else {
2N/A /* ignore ENOENT here */
2N/A r = 0;
2N/A }
2N/A } else {
2N/A tokenmatch = TRUE;
2N/A }
2N/A } else {
2N/A /* + 1 so tokenlabelstr can be \0 terminated */
2N/A char tokenlabelstr[sizeof (tinfo.label) + 1];
2N/A
2N/A /*
2N/A * Convert token label into C string with trailing white space
2N/A * trimmed.
2N/A */
2N/A trim_token_label(&tinfo, tokenlabelstr, sizeof (tokenlabelstr));
2N/A
2N/A pkiDebug("open_session: slotid %d token found: \"%s\", "
2N/A "cctx->token_label: \"%s\"\n",
2N/A slotlist[i], tokenlabelstr, (char *) cctx->token_label);
2N/A
2N/A if (!strcmp(cctx->token_label, tokenlabelstr)) {
2N/A if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
2N/A /*
2N/A * It's okay to check the certs if we don't have to login but
2N/A * don't load the certs onto cctx at this point, this will be
2N/A * done later in this function for the chosen token.
2N/A */
2N/A if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
2N/A req_cryptoctx, cctx, princ,
2N/A do_matching, 0)) == 0) {
2N/A tokenmatch = TRUE;
2N/A } else if (r != ENOENT){
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A cctx->p11->C_CloseSession(tmpsession);
2N/A goto out;
2N/A } else {
2N/A /* ignore ENOENT here */
2N/A r = 0;
2N/A }
2N/A } else {
2N/A tokenmatch = TRUE;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (tokenmatch == TRUE) {
2N/A /* add the token to token_choices.token_array */
2N/A token_choices.token_array[token_choices.numtokens].slotID = slotlist[i];
2N/A token_choices.token_array[token_choices.numtokens].session = tmpsession;
2N/A token_choices.token_array[token_choices.numtokens].token_info = tinfo;
2N/A token_choices.numtokens++;
2N/A /* !do_matching implies we take the first matching token */
2N/A if (!do_matching)
2N/A break;
2N/A else
2N/A tokenmatch = FALSE;
2N/A } else {
2N/A cctx->p11->C_CloseSession(tmpsession);
2N/A }
2N/A }
2N/A
2N/A if (token_choices.numtokens == 0) {
2N/A /*
2N/A * Solaris Kerberos: prompt for token one time if there was no token
2N/A * and do_matching is 1 (see earlier comment about do_matching).
2N/A */
2N/A if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
2N/A if ((r = pkinit_prompt_token(context, cctx)) == 0) {
2N/A cctx->p11flags |= C_PROMPTED_USER;
2N/A goto tryagain;
2N/A } else {
2N/A pkiDebug("open_session: prompt for token/smart card failed\n");
2N/A krb5_set_error_message(context, r,
2N/A gettext("Prompt for token/smart card failed"));
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A } else {
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, r,
2N/A gettext("No smart card tokens found"));
2N/A pkiDebug("open_session: no matching token found\n");
2N/A goto out;
2N/A }
2N/A } else if (token_choices.numtokens == 1) {
2N/A if ((token_choices.token_array[0].token_info.flags & CKF_LOGIN_REQUIRED) &&
2N/A !(cctx->p11flags & C_PROMPTED_USER) &&
2N/A do_matching) {
2N/A if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
2N/A pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, r,
2N/A gettext("Prompt for token/smart card failed"));
2N/A goto out;
2N/A }
2N/A if (choice == RESCAN_TOKENS) {
2N/A /* rescan for new smartcard/token */
2N/A for (i = 0; i < token_choices.numtokens; i++) {
2N/A /* close all sessions */
2N/A cctx->p11->C_CloseSession(token_choices.token_array[i].session);
2N/A }
2N/A free(token_choices.token_array);
2N/A token_choices.token_array = NULL;
2N/A token_choices.numtokens = 0;
2N/A goto tryagain;
2N/A } else if (choice == SKIP_TOKENS) {
2N/A /* do not use smartcard/token for auth */
2N/A cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A } else {
2N/A cctx->p11flags |= C_PROMPTED_USER;
2N/A }
2N/A } else {
2N/A choice = 0; /* really the only choice is the first token_array entry */
2N/A }
2N/A } else if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
2N/A /* > 1 token so present menu of token choices, let the user decide. */
2N/A if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
2N/A pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A krb5_set_error_message(context, r,
2N/A gettext("Prompt for token/smart card failed"));
2N/A goto out;
2N/A }
2N/A if (choice == RESCAN_TOKENS) {
2N/A /* rescan for new smartcard/token */
2N/A for (i = 0; i < token_choices.numtokens; i++) {
2N/A /* close all sessions */
2N/A cctx->p11->C_CloseSession(token_choices.token_array[i].session);
2N/A }
2N/A free(token_choices.token_array);
2N/A token_choices.token_array = NULL;
2N/A token_choices.numtokens = 0;
2N/A goto tryagain;
2N/A } else if (choice == SKIP_TOKENS) {
2N/A /* do not use smartcard/token for auth */
2N/A cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A } else {
2N/A cctx->p11flags |= C_PROMPTED_USER;
2N/A }
2N/A } else {
2N/A r = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A goto out;
2N/A }
2N/A
2N/A cctx->slotid = token_choices.token_array[choice].slotID;
2N/A cctx->session = token_choices.token_array[choice].session;
2N/A
2N/A pkiDebug("open_session: slotid %d (%d of %d)\n", (int) cctx->slotid,
2N/A i + 1, (int) count);
2N/A
2N/A /* Login if needed */
2N/A /* Solaris Kerberos: added cctx->p11flags check */
2N/A if ((token_choices.token_array[choice].token_info.flags & CKF_LOGIN_REQUIRED) &&
2N/A !(cctx->p11flags & C_LOGIN_DONE)) {
2N/A r = pkinit_login(context, cctx, &token_choices.token_array[choice].token_info);
2N/A }
2N/A
2N/A if (r == 0) {
2N/A /* Doing this again to load the certs into cctx. */
2N/A r = check_load_certs(context, cctx->session, plg_cryptoctx,
2N/A req_cryptoctx, cctx, princ, do_matching, 1);
2N/A }
2N/A
2N/Aout:
2N/A if (slotlist != NULL)
2N/A free(slotlist);
2N/A
2N/A if (tmpslotlist != NULL)
2N/A free(tmpslotlist);
2N/A
2N/A if (token_choices.token_array != NULL) {
2N/A if (r != 0) {
2N/A /* close all sessions if there's an error */
2N/A for (i = 0; i < token_choices.numtokens; i++) {
2N/A cctx->p11->C_CloseSession(token_choices.token_array[i].session);
2N/A }
2N/A cctx->session = CK_INVALID_HANDLE;
2N/A } else {
2N/A /* close sessions not chosen */
2N/A for (i = 0; i < token_choices.numtokens; i++) {
2N/A if (i != choice) {
2N/A cctx->p11->C_CloseSession(token_choices.token_array[i].session);
2N/A }
2N/A }
2N/A }
2N/A free(token_choices.token_array);
2N/A }
2N/A
2N/A return (r);
2N/A}
2N/A
2N/A/*
2N/A * Look for a key that's:
2N/A * 1. private
2N/A * 2. capable of the specified operation (usually signing or decrypting)
2N/A * 3. RSA (this may be wrong but it's all we can do for now)
2N/A * 4. matches the id of the cert we chose
2N/A *
2N/A * You must call pkinit_get_certs before calling pkinit_find_private_key
2N/A * (that's because we need the ID of the private key)
2N/A *
2N/A * pkcs11 says the id of the key doesn't have to match that of the cert, but
2N/A * I can't figure out any other way to decide which key to use.
2N/A *
2N/A * We should only find one key that fits all the requirements.
2N/A * If there are more than one, we just take the first one.
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Apkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
2N/A CK_ATTRIBUTE_TYPE usage,
2N/A CK_OBJECT_HANDLE *objp)
2N/A{
2N/A CK_OBJECT_CLASS cls;
2N/A CK_ATTRIBUTE attrs[4];
2N/A CK_ULONG count;
2N/A CK_KEY_TYPE keytype;
2N/A unsigned int nattrs = 0;
2N/A int r;
2N/A#ifdef PKINIT_USE_KEY_USAGE
2N/A CK_BBOOL true_false;
2N/A#endif
2N/A
2N/A cls = CKO_PRIVATE_KEY;
2N/A attrs[nattrs].type = CKA_CLASS;
2N/A attrs[nattrs].pValue = &cls;
2N/A attrs[nattrs].ulValueLen = sizeof cls;
2N/A nattrs++;
2N/A
2N/A#ifdef PKINIT_USE_KEY_USAGE
2N/A /*
2N/A * Some cards get confused if you try to specify a key usage,
2N/A * so don't, and hope for the best. This will fail if you have
2N/A * several keys with the same id and different usages but I have
2N/A * not seen this on real cards.
2N/A */
2N/A true_false = TRUE;
2N/A attrs[nattrs].type = usage;
2N/A attrs[nattrs].pValue = &true_false;
2N/A attrs[nattrs].ulValueLen = sizeof true_false;
2N/A nattrs++;
2N/A#endif
2N/A
2N/A keytype = CKK_RSA;
2N/A attrs[nattrs].type = CKA_KEY_TYPE;
2N/A attrs[nattrs].pValue = &keytype;
2N/A attrs[nattrs].ulValueLen = sizeof keytype;
2N/A nattrs++;
2N/A
2N/A attrs[nattrs].type = CKA_ID;
2N/A attrs[nattrs].pValue = id_cryptoctx->cert_id;
2N/A attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
2N/A nattrs++;
2N/A
2N/A r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
2N/A if (r != CKR_OK) {
2N/A pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
2N/A pkinit_pkcs11_code_to_text(r));
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A
2N/A r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
2N/A id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
2N/A pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
2N/A
2N/A /*
2N/A * Solaris Kerberos:
2N/A * The CKA_ID may not be correctly set for the private key. For e.g. when
2N/A * storing a private key in softtoken pktool(1) doesn't generate or store
2N/A * a CKA_ID for the private key. Another way to identify the private key is
2N/A * to look for a private key with the same RSA modulus as the public key
2N/A * in the certificate.
2N/A */
2N/A if (r == CKR_OK && count != 1) {
2N/A
2N/A EVP_PKEY *priv;
2N/A X509 *cert;
2N/A unsigned int n_len;
2N/A unsigned char *n_bytes;
2N/A
2N/A cert = sk_X509_value(id_cryptoctx->my_certs, 0);
2N/A priv = X509_get_pubkey(cert);
2N/A if (priv == NULL) {
2N/A pkiDebug("Failed to extract pub key from cert\n");
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A
2N/A nattrs = 0;
2N/A cls = CKO_PRIVATE_KEY;
2N/A attrs[nattrs].type = CKA_CLASS;
2N/A attrs[nattrs].pValue = &cls;
2N/A attrs[nattrs].ulValueLen = sizeof cls;
2N/A nattrs++;
2N/A
2N/A#ifdef PKINIT_USE_KEY_USAGE
2N/A true_false = TRUE;
2N/A attrs[nattrs].type = usage;
2N/A attrs[nattrs].pValue = &true_false;
2N/A attrs[nattrs].ulValueLen = sizeof true_false;
2N/A nattrs++;
2N/A#endif
2N/A
2N/A keytype = CKK_RSA;
2N/A attrs[nattrs].type = CKA_KEY_TYPE;
2N/A attrs[nattrs].pValue = &keytype;
2N/A attrs[nattrs].ulValueLen = sizeof keytype;
2N/A nattrs++;
2N/A
2N/A n_len = BN_num_bytes(priv->pkey.rsa->n);
2N/A n_bytes = (unsigned char *) malloc((size_t) n_len);
2N/A if (n_bytes == NULL) {
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (BN_bn2bin(priv->pkey.rsa->n, n_bytes) == 0) {
2N/A free (n_bytes);
2N/A pkiDebug("zero-byte key modulus\n");
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A
2N/A attrs[nattrs].type = CKA_MODULUS;
2N/A attrs[nattrs].ulValueLen = n_len;
2N/A attrs[nattrs].pValue = n_bytes;
2N/A
2N/A nattrs++;
2N/A
2N/A r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
2N/A free (n_bytes);
2N/A if (r != CKR_OK) {
2N/A pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
2N/A pkinit_pkcs11_code_to_text(r));
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A
2N/A r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
2N/A id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
2N/A pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
2N/A
2N/A }
2N/A
2N/A if (r != CKR_OK || count < 1)
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A return 0;
2N/A}
2N/A#endif
2N/A
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Apkinit_decode_data_fs(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *data,
2N/A unsigned int data_len,
2N/A unsigned char **decoded_data,
2N/A unsigned int *decoded_data_len)
2N/A{
2N/A if (decode_data(decoded_data, decoded_data_len, data, data_len,
2N/A id_cryptoctx->my_key, sk_X509_value(id_cryptoctx->my_certs,
2N/A id_cryptoctx->cert_index)) <= 0) {
2N/A pkiDebug("failed to decode data\n");
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A return 0;
2N/A}
2N/A
2N/A#ifndef WITHOUT_PKCS11
2N/A#ifdef SILLYDECRYPT
2N/ACK_RV
2N/Apkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
2N/A CK_BYTE_PTR pEncryptedData,
2N/A CK_ULONG ulEncryptedDataLen,
2N/A CK_BYTE_PTR pData,
2N/A CK_ULONG_PTR pulDataLen)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A
2N/A rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
2N/A ulEncryptedDataLen, pData, pulDataLen);
2N/A if (rv == CKR_OK) {
2N/A pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
2N/A }
2N/A return rv;
2N/A}
2N/A#endif
2N/A
2N/Astatic krb5_error_code
2N/Apkinit_decode_data_pkcs11(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *data,
2N/A unsigned int data_len,
2N/A unsigned char **decoded_data,
2N/A unsigned int *decoded_data_len)
2N/A{
2N/A CK_OBJECT_HANDLE obj;
2N/A CK_ULONG len;
2N/A CK_MECHANISM mech;
2N/A unsigned char *cp;
2N/A int r;
2N/A
2N/A /*
2N/A * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
2N/A * loaded.
2N/A */
2N/A assert(id_cryptoctx->p11 != NULL);
2N/A
2N/A /* Solaris Kerberos: Login, if needed, to access private object */
2N/A if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
2N/A CK_TOKEN_INFO tinfo;
2N/A
2N/A r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
2N/A if (r != 0)
2N/A return r;
2N/A
2N/A r = pkinit_login(context, id_cryptoctx, &tinfo);
2N/A if (r != 0)
2N/A return r;
2N/A }
2N/A
2N/A r = pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj);
2N/A if (r != 0)
2N/A return r;
2N/A
2N/A mech.mechanism = CKM_RSA_PKCS;
2N/A mech.pParameter = NULL;
2N/A mech.ulParameterLen = 0;
2N/A
2N/A if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech,
2N/A obj)) != CKR_OK) {
2N/A pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A pkiDebug("data_len = %d\n", data_len);
2N/A cp = (unsigned char *)malloc((size_t) data_len);
2N/A if (cp == NULL)
2N/A return ENOMEM;
2N/A len = data_len;
2N/A#ifdef SILLYDECRYPT
2N/A pkiDebug("session %x edata %x edata_len %d data %x datalen @%x %d\n",
2N/A (int) id_cryptoctx->session, (int) data, (int) data_len, (int) cp,
2N/A (int) &len, (int) len);
2N/A if ((r = pkinit_C_Decrypt(id_cryptoctx, data, (CK_ULONG) data_len,
2N/A cp, &len)) != CKR_OK) {
2N/A#else
2N/A if ((r = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, data,
2N/A (CK_ULONG) data_len, cp, &len)) != CKR_OK) {
2N/A#endif
2N/A pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A if (r == CKR_BUFFER_TOO_SMALL)
2N/A pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
2N/A *decoded_data_len = len;
2N/A *decoded_data = cp;
2N/A
2N/A return 0;
2N/A}
2N/A#endif
2N/A
2N/Akrb5_error_code
2N/Apkinit_decode_data(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *data,
2N/A unsigned int data_len,
2N/A unsigned char **decoded_data,
2N/A unsigned int *decoded_data_len)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A
2N/A if (id_cryptoctx->pkcs11_method != 1)
2N/A retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len,
2N/A decoded_data, decoded_data_len);
2N/A#ifndef WITHOUT_PKCS11
2N/A else
2N/A retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data,
2N/A data_len, decoded_data, decoded_data_len);
2N/A#endif
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Apkinit_sign_data_fs(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *data,
2N/A unsigned int data_len,
2N/A unsigned char **sig,
2N/A unsigned int *sig_len)
2N/A{
2N/A if (create_signature(sig, sig_len, data, data_len,
2N/A id_cryptoctx->my_key) != 0) {
2N/A pkiDebug("failed to create the signature\n");
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A return 0;
2N/A}
2N/A
2N/A#ifndef WITHOUT_PKCS11
2N/Astatic krb5_error_code
2N/Apkinit_sign_data_pkcs11(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *data,
2N/A unsigned int data_len,
2N/A unsigned char **sig,
2N/A unsigned int *sig_len)
2N/A{
2N/A CK_OBJECT_HANDLE obj;
2N/A CK_ULONG len;
2N/A CK_MECHANISM mech;
2N/A unsigned char *cp;
2N/A int r;
2N/A
2N/A /*
2N/A * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
2N/A * loaded.
2N/A */
2N/A assert(id_cryptoctx->p11 != NULL);
2N/A
2N/A /* Solaris Kerberos: Login, if needed, to access private object */
2N/A if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
2N/A CK_TOKEN_INFO tinfo;
2N/A
2N/A r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
2N/A if (r != 0)
2N/A return r;
2N/A
2N/A r = pkinit_login(context, id_cryptoctx, &tinfo);
2N/A if (r != 0)
2N/A return r;
2N/A }
2N/A
2N/A r = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
2N/A if (r != 0 )
2N/A return r;
2N/A
2N/A mech.mechanism = id_cryptoctx->mech;
2N/A mech.pParameter = NULL;
2N/A mech.ulParameterLen = 0;
2N/A
2N/A if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
2N/A obj)) != CKR_OK) {
2N/A pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A
2N/A /*
2N/A * Key len would give an upper bound on sig size, but there's no way to
2N/A * get that. So guess, and if it's too small, re-malloc.
2N/A */
2N/A len = PK_SIGLEN_GUESS;
2N/A cp = (unsigned char *)malloc((size_t) len);
2N/A if (cp == NULL)
2N/A return ENOMEM;
2N/A
2N/A r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
2N/A (CK_ULONG) data_len, cp, &len);
2N/A if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
2N/A free(cp);
2N/A pkiDebug("C_Sign realloc %d\n", (int) len);
2N/A cp = (unsigned char *)malloc((size_t) len);
2N/A r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
2N/A (CK_ULONG) data_len, cp, &len);
2N/A }
2N/A if (r != CKR_OK) {
2N/A pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
2N/A *sig_len = len;
2N/A *sig = cp;
2N/A
2N/A return 0;
2N/A}
2N/A#endif
2N/A
2N/Akrb5_error_code
2N/Apkinit_sign_data(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char *data,
2N/A unsigned int data_len,
2N/A unsigned char **sig,
2N/A unsigned int *sig_len)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A
2N/A if (id_cryptoctx == NULL || id_cryptoctx->pkcs11_method != 1)
2N/A retval = pkinit_sign_data_fs(context, id_cryptoctx, data, data_len,
2N/A sig, sig_len);
2N/A#ifndef WITHOUT_PKCS11
2N/A else
2N/A retval = pkinit_sign_data_pkcs11(context, id_cryptoctx, data, data_len,
2N/A sig, sig_len);
2N/A#endif
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A
2N/Astatic krb5_error_code
2N/Adecode_data(unsigned char **out_data, unsigned int *out_data_len,
2N/A unsigned char *data, unsigned int data_len,
2N/A EVP_PKEY *pkey, X509 *cert)
2N/A{
2N/A /* Solaris Kerberos */
2N/A int len;
2N/A unsigned char *buf = NULL;
2N/A int buf_len = 0;
2N/A
2N/A /* Solaris Kerberos */
2N/A if (out_data == NULL || out_data_len == NULL)
2N/A return EINVAL;
2N/A
2N/A if (cert && !X509_check_private_key(cert, pkey)) {
2N/A pkiDebug("private key does not match certificate\n");
2N/A /* Solaris Kerberos */
2N/A return EINVAL;
2N/A }
2N/A
2N/A buf_len = EVP_PKEY_size(pkey);
2N/A buf = (unsigned char *)malloc((size_t) buf_len + 10);
2N/A if (buf == NULL)
2N/A return ENOMEM;
2N/A#if OPENSSL_VERSION_NUMBER >= 0x00909000L
2N/A len = EVP_PKEY_decrypt_old(buf, data, (int)data_len, pkey);
2N/A#else
2N/A len = EVP_PKEY_decrypt(buf, data, (int)data_len, pkey);
2N/A#endif
2N/A if (len <= 0) {
2N/A pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
2N/A /* Solaris Kerberos */
2N/A free(buf);
2N/A return KRB5KRB_ERR_GENERIC;
2N/A }
2N/A *out_data = buf;
2N/A *out_data_len = len;
2N/A
2N/A return 0;
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Acreate_signature(unsigned char **sig, unsigned int *sig_len,
2N/A unsigned char *data, unsigned int data_len, EVP_PKEY *pkey)
2N/A{
2N/A krb5_error_code retval = ENOMEM;
2N/A EVP_MD_CTX md_ctx;
2N/A
2N/A if (pkey == NULL)
2N/A /* Solaris Kerberos */
2N/A return EINVAL;
2N/A
2N/A EVP_VerifyInit(&md_ctx, EVP_sha1());
2N/A EVP_SignUpdate(&md_ctx, data, data_len);
2N/A *sig_len = EVP_PKEY_size(pkey);
2N/A if ((*sig = (unsigned char *) malloc((size_t) *sig_len)) == NULL)
2N/A goto cleanup;
2N/A EVP_SignFinal(&md_ctx, *sig, sig_len, pkey);
2N/A
2N/A retval = 0;
2N/A
2N/A cleanup:
2N/A EVP_MD_CTX_cleanup(&md_ctx);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/*
2N/A * Note:
2N/A * This is not the routine the KDC uses to get its certificate.
2N/A * This routine is intended to be called by the client
2N/A * to obtain the KDC's certificate from some local storage
2N/A * to be sent as a hint in its request to the KDC.
2N/A */
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Apkinit_get_kdc_cert(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_principal princ)
2N/A{
2N/A /* Solaris Kerberos */
2N/A if (req_cryptoctx == NULL)
2N/A return EINVAL;
2N/A
2N/A req_cryptoctx->received_cert = NULL;
2N/A return 0;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Apkinit_get_certs_pkcs12(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_opts *idopts,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_principal princ)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A X509 *x = NULL;
2N/A PKCS12 *p12 = NULL;
2N/A int ret;
2N/A FILE *fp;
2N/A EVP_PKEY *y = NULL;
2N/A
2N/A if (idopts->cert_filename == NULL) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, retval,
2N/A gettext("Failed to get certificate location"));
2N/A pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (idopts->key_filename == NULL) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, retval,
2N/A gettext("Failed to get private key location"));
2N/A pkiDebug("%s: failed to get user's private key location\n", __FUNCTION__);
2N/A goto cleanup;
2N/A }
2N/A
2N/A fp = fopen(idopts->cert_filename, "rb");
2N/A if (fp == NULL) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, retval,
2N/A gettext("Failed to open PKCS12 file '%s': %s"),
2N/A idopts->cert_filename, error_message(errno));
2N/A pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
2N/A idopts->cert_filename, errno);
2N/A goto cleanup;
2N/A }
2N/A
2N/A p12 = d2i_PKCS12_fp(fp, NULL);
2N/A (void) fclose(fp);
2N/A if (p12 == NULL) {
2N/A krb5_set_error_message(context, retval,
2N/A gettext("Failed to decode PKCS12 file '%s' contents"),
2N/A idopts->cert_filename);
2N/A pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
2N/A idopts->cert_filename);
2N/A goto cleanup;
2N/A }
2N/A /*
2N/A * Try parsing with no pass phrase first. If that fails,
2N/A * prompt for the pass phrase and try again.
2N/A */
2N/A ret = PKCS12_parse(p12, NULL, &y, &x, NULL);
2N/A if (ret == 0) {
2N/A krb5_data rdat;
2N/A krb5_prompt kprompt;
2N/A krb5_prompt_type prompt_type;
2N/A int r = 0;
2N/A char prompt_string[128];
2N/A char prompt_reply[128];
2N/A /* Solaris Kerberos */
2N/A char *prompt_prefix = gettext("Pass phrase for");
2N/A
2N/A pkiDebug("Initial PKCS12_parse with no password failed\n");
2N/A
2N/A if (id_cryptoctx->PIN != NULL) {
2N/A /* Solaris Kerberos: use PIN if set */
2N/A rdat.data = id_cryptoctx->PIN;
2N/A /* note rdat.length isn't needed in this case */
2N/A } else {
2N/A (void) memset(prompt_reply, '\0', sizeof(prompt_reply));
2N/A rdat.data = prompt_reply;
2N/A rdat.length = sizeof(prompt_reply);
2N/A
2N/A r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
2N/A prompt_prefix, idopts->cert_filename);
2N/A if (r >= sizeof(prompt_string)) {
2N/A pkiDebug("Prompt string, '%s %s', is too long!\n",
2N/A prompt_prefix, idopts->cert_filename);
2N/A goto cleanup;
2N/A }
2N/A kprompt.prompt = prompt_string;
2N/A kprompt.hidden = 1;
2N/A kprompt.reply = &rdat;
2N/A prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
2N/A
2N/A /* PROMPTER_INVOCATION */
2N/A k5int_set_prompt_types(context, &prompt_type);
2N/A r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
2N/A NULL, NULL, 1, &kprompt);
2N/A k5int_set_prompt_types(context, NULL);
2N/A }
2N/A
2N/A ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
2N/A if (ret == 0) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, retval,
2N/A gettext("Failed to parse PKCS12 file '%s' with password"),
2N/A idopts->cert_filename);
2N/A pkiDebug("Seconde PKCS12_parse with password failed\n");
2N/A goto cleanup;
2N/A }
2N/A }
2N/A id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
2N/A if (id_cryptoctx->creds[0] == NULL)
2N/A goto cleanup;
2N/A id_cryptoctx->creds[0]->cert = x;
2N/A#ifndef WITHOUT_PKCS11
2N/A id_cryptoctx->creds[0]->cert_id = NULL;
2N/A id_cryptoctx->creds[0]->cert_id_len = 0;
2N/A#endif
2N/A id_cryptoctx->creds[0]->key = y;
2N/A id_cryptoctx->creds[1] = NULL;
2N/A
2N/A retval = 0;
2N/A
2N/Acleanup:
2N/A if (p12)
2N/A PKCS12_free(p12);
2N/A if (retval) {
2N/A if (x != NULL)
2N/A X509_free(x);
2N/A if (y != NULL)
2N/A EVP_PKEY_free(y);
2N/A }
2N/A return retval;
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Apkinit_load_fs_cert_and_key(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A char *certname,
2N/A char *keyname,
2N/A int cindex)
2N/A{
2N/A krb5_error_code retval;
2N/A X509 *x = NULL;
2N/A EVP_PKEY *y = NULL;
2N/A
2N/A /* load the certificate */
2N/A retval = get_cert(certname, &x);
2N/A if (retval != 0 || x == NULL) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, retval,
2N/A gettext("Failed to load user's certificate from %s: %s"),
2N/A certname, error_message(retval));
2N/A pkiDebug("failed to load user's certificate from '%s'\n", certname);
2N/A goto cleanup;
2N/A }
2N/A retval = get_key(keyname, &y);
2N/A if (retval != 0 || y == NULL) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, retval,
2N/A gettext("Failed to load user's private key from %s: %s"),
2N/A keyname, error_message(retval));
2N/A pkiDebug("failed to load user's private key from '%s'\n", keyname);
2N/A goto cleanup;
2N/A }
2N/A
2N/A id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
2N/A if (id_cryptoctx->creds[cindex] == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A id_cryptoctx->creds[cindex]->cert = x;
2N/A#ifndef WITHOUT_PKCS11
2N/A id_cryptoctx->creds[cindex]->cert_id = NULL;
2N/A id_cryptoctx->creds[cindex]->cert_id_len = 0;
2N/A#endif
2N/A id_cryptoctx->creds[cindex]->key = y;
2N/A id_cryptoctx->creds[cindex+1] = NULL;
2N/A
2N/A retval = 0;
2N/A
2N/Acleanup:
2N/A if (retval) {
2N/A if (x != NULL)
2N/A X509_free(x);
2N/A if (y != NULL)
2N/A EVP_PKEY_free(y);
2N/A }
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Apkinit_get_certs_fs(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_opts *idopts,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_principal princ)
2N/A{
2N/A krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/A
2N/A if (idopts->cert_filename == NULL) {
2N/A pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (idopts->key_filename == NULL) {
2N/A pkiDebug("%s: failed to get user's private key location\n",
2N/A __FUNCTION__);
2N/A goto cleanup;
2N/A }
2N/A
2N/A retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
2N/A idopts->cert_filename,
2N/A idopts->key_filename, 0);
2N/Acleanup:
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Apkinit_get_certs_dir(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_opts *idopts,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_principal princ)
2N/A{
2N/A /* Solaris Kerberos */
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A DIR *d = NULL;
2N/A struct dirent *dentry = NULL;
2N/A char certname[1024];
2N/A char keyname[1024];
2N/A int i = 0, len;
2N/A char *dirname, *suf;
2N/A
2N/A /* Solaris Kerberos */
2N/A if (idopts == NULL)
2N/A return EINVAL;
2N/A
2N/A if (idopts->cert_filename == NULL) {
2N/A pkiDebug("%s: failed to get user's certificate directory location\n",
2N/A __FUNCTION__);
2N/A return ENOENT;
2N/A }
2N/A
2N/A dirname = idopts->cert_filename;
2N/A d = opendir(dirname);
2N/A if (d == NULL) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, errno,
2N/A gettext("Failed to open directory \"%s\": %s"),
2N/A dirname, error_message(errno));
2N/A return errno;
2N/A }
2N/A
2N/A /*
2N/A * We'll assume that certs are named XXX.crt and the corresponding
2N/A * key is named XXX.key
2N/A */
2N/A while ((i < MAX_CREDS_ALLOWED) && (dentry = readdir(d)) != NULL) {
2N/A /* Ignore subdirectories and anything starting with a dot */
2N/A#ifdef DT_DIR
2N/A if (dentry->d_type == DT_DIR)
2N/A continue;
2N/A#endif
2N/A if (dentry->d_name[0] == '.')
2N/A continue;
2N/A len = strlen(dentry->d_name);
2N/A if (len < 5)
2N/A continue;
2N/A suf = dentry->d_name + (len - 4);
2N/A if (strncmp(suf, ".crt", 4) != 0)
2N/A continue;
2N/A
2N/A /* Checked length */
2N/A if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(certname)) {
2N/A pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
2N/A __FUNCTION__, dirname, dentry->d_name);
2N/A continue;
2N/A }
2N/A (void) snprintf(certname, sizeof(certname), "%s/%s", dirname, dentry->d_name);
2N/A (void) snprintf(keyname, sizeof(keyname), "%s/%s", dirname, dentry->d_name);
2N/A len = strlen(keyname);
2N/A keyname[len - 3] = 'k';
2N/A keyname[len - 2] = 'e';
2N/A keyname[len - 1] = 'y';
2N/A
2N/A retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
2N/A certname, keyname, i);
2N/A if (retval == 0) {
2N/A pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
2N/A __FUNCTION__, dentry->d_name);
2N/A i++;
2N/A }
2N/A else
2N/A continue;
2N/A }
2N/A
2N/A if (i == 0) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A krb5_set_error_message(context, ENOENT,
2N/A gettext("No suitable cert/key pairs found in directory '%s'"),
2N/A idopts->cert_filename);
2N/A pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
2N/A __FUNCTION__, idopts->cert_filename);
2N/A retval = ENOENT;
2N/A goto cleanup;
2N/A }
2N/A
2N/A retval = 0;
2N/A
2N/A cleanup:
2N/A if (d)
2N/A (void) closedir(d);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A#ifndef WITHOUT_PKCS11
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Apkinit_get_certs_pkcs11(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_opts *idopts,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_principal princ,
2N/A int do_matching)
2N/A{
2N/A#ifdef PKINIT_USE_MECH_LIST
2N/A CK_MECHANISM_TYPE_PTR mechp = NULL;
2N/A CK_MECHANISM_INFO info;
2N/A#endif
2N/A
2N/A if (id_cryptoctx->p11flags & C_SKIP_PKCS11_AUTH)
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A
2N/A /* Copy stuff from idopts -> id_cryptoctx */
2N/A if (idopts->p11_module_name != NULL) {
2N/A id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
2N/A if (id_cryptoctx->p11_module_name == NULL)
2N/A return ENOMEM;
2N/A }
2N/A if (idopts->token_label != NULL) {
2N/A id_cryptoctx->token_label = strdup(idopts->token_label);
2N/A if (id_cryptoctx->token_label == NULL)
2N/A return ENOMEM;
2N/A }
2N/A if (idopts->cert_label != NULL) {
2N/A id_cryptoctx->cert_label = strdup(idopts->cert_label);
2N/A if (id_cryptoctx->cert_label == NULL)
2N/A return ENOMEM;
2N/A }
2N/A if (idopts->PIN != NULL) {
2N/A id_cryptoctx->PIN = strdup(idopts->PIN);
2N/A if (id_cryptoctx->PIN == NULL)
2N/A return ENOMEM;
2N/A }
2N/A /* Convert the ascii cert_id string into a binary blob */
2N/A /*
2N/A * Solaris Kerberos:
2N/A * If the cert_id_string is empty then behave in a similar way to how
2N/A * an empty certlabel is treated - i.e. don't fail now but rather continue
2N/A * as though the certid wasn't specified.
2N/A */
2N/A if (idopts->cert_id_string != NULL && strlen(idopts->cert_id_string) != 0) {
2N/A BIGNUM *bn = NULL;
2N/A BN_hex2bn(&bn, idopts->cert_id_string);
2N/A if (bn == NULL)
2N/A return ENOMEM;
2N/A id_cryptoctx->cert_id_len = BN_num_bytes(bn);
2N/A id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
2N/A if (id_cryptoctx->cert_id == NULL) {
2N/A BN_free(bn);
2N/A return ENOMEM;
2N/A }
2N/A BN_bn2bin(bn, id_cryptoctx->cert_id);
2N/A BN_free(bn);
2N/A }
2N/A id_cryptoctx->slotid = idopts->slotid;
2N/A id_cryptoctx->pkcs11_method = 1;
2N/A
2N/A#ifndef PKINIT_USE_MECH_LIST
2N/A /*
2N/A * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
2N/A * many cards seems to be confused about whether they are capable of
2N/A * this or not. The safe thing seems to be to ignore the mechanism list,
2N/A * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
2N/A */
2N/A
2N/A id_cryptoctx->mech = CKM_RSA_PKCS;
2N/A#else
2N/A if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL,
2N/A &count)) != CKR_OK || count <= 0) {
2N/A pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r));
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A mechp = (CK_MECHANISM_TYPE_PTR) malloc(count * sizeof (CK_MECHANISM_TYPE));
2N/A if (mechp == NULL)
2N/A return ENOMEM;
2N/A if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid,
2N/A mechp, &count)) != CKR_OK) {
2N/A free(mechp);
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A for (i = 0; i < count; i++) {
2N/A if ((r = id_cryptoctx->p11->C_GetMechanismInfo(id_cryptoctx->slotid,
2N/A mechp[i], &info)) != CKR_OK) {
2N/A free(mechp);
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A }
2N/A#ifdef DEBUG_MECHINFO
2N/A pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
2N/A if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
2N/A pkiDebug(" this mech is good for sign & decrypt\n");
2N/A#endif
2N/A if (mechp[i] == CKM_RSA_PKCS) {
2N/A /* This seems backwards... */
2N/A id_cryptoctx->mech =
2N/A (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
2N/A }
2N/A }
2N/A free(mechp);
2N/A
2N/A pkiDebug("got %d mechs from card\n", (int) count);
2N/A#endif
2N/A
2N/A return (pkinit_open_session(context, plg_cryptoctx, req_cryptoctx,
2N/A id_cryptoctx, princ, do_matching));
2N/A}
2N/A#endif
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Afree_cred_info(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A struct _pkinit_cred_info *cred)
2N/A{
2N/A if (cred != NULL) {
2N/A if (cred->cert != NULL)
2N/A X509_free(cred->cert);
2N/A if (cred->key != NULL)
2N/A EVP_PKEY_free(cred->key);
2N/A#ifndef WITHOUT_PKCS11
2N/A if (cred->cert_id != NULL)
2N/A free(cred->cert_id);
2N/A#endif
2N/A free(cred);
2N/A }
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_free_cert_info(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx)
2N/A{
2N/A int i;
2N/A
2N/A if (id_cryptoctx == NULL)
2N/A return EINVAL;
2N/A
2N/A for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
2N/A if (id_cryptoctx->creds[i] != NULL) {
2N/A free_cred_info(context, id_cryptoctx, id_cryptoctx->creds[i]);
2N/A id_cryptoctx->creds[i] = NULL;
2N/A }
2N/A }
2N/A return 0;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Acrypto_load_certs(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_opts *idopts,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_principal princ,
2N/A int do_matching)
2N/A{
2N/A krb5_error_code retval;
2N/A
2N/A switch(idopts->idtype) {
2N/A case IDTYPE_FILE:
2N/A retval = pkinit_get_certs_fs(context, plg_cryptoctx,
2N/A req_cryptoctx, idopts,
2N/A id_cryptoctx, princ);
2N/A break;
2N/A case IDTYPE_DIR:
2N/A retval = pkinit_get_certs_dir(context, plg_cryptoctx,
2N/A req_cryptoctx, idopts,
2N/A id_cryptoctx, princ);
2N/A break;
2N/A#ifndef WITHOUT_PKCS11
2N/A case IDTYPE_PKCS11:
2N/A retval = pkinit_get_certs_pkcs11(context, plg_cryptoctx,
2N/A req_cryptoctx, idopts,
2N/A id_cryptoctx, princ, do_matching);
2N/A break;
2N/A#endif
2N/A case IDTYPE_PKCS12:
2N/A retval = pkinit_get_certs_pkcs12(context, plg_cryptoctx,
2N/A req_cryptoctx, idopts,
2N/A id_cryptoctx, princ);
2N/A break;
2N/A default:
2N/A retval = EINVAL;
2N/A }
2N/A/* Solaris Kerberos */
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/*
2N/A * Get number of certificates available after crypto_load_certs()
2N/A */
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_cert_get_count(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A int *cert_count)
2N/A{
2N/A int count;
2N/A
2N/A if (id_cryptoctx == NULL || id_cryptoctx->creds[0] == NULL)
2N/A return EINVAL;
2N/A
2N/A for (count = 0;
2N/A count <= MAX_CREDS_ALLOWED && id_cryptoctx->creds[count] != NULL;
2N/A count++);
2N/A *cert_count = count;
2N/A return 0;
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Begin iteration over the certs loaded in crypto_load_certs()
2N/A */
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_cert_iteration_begin(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A pkinit_cert_iter_handle *ih_ret)
2N/A{
2N/A struct _pkinit_cert_iter_data *id;
2N/A
2N/A if (id_cryptoctx == NULL || ih_ret == NULL)
2N/A return EINVAL;
2N/A if (id_cryptoctx->creds[0] == NULL) /* No cred info available */
2N/A return ENOENT;
2N/A
2N/A id = calloc(1, sizeof(*id));
2N/A if (id == NULL)
2N/A return ENOMEM;
2N/A id->magic = ITER_MAGIC;
2N/A id->plgctx = plg_cryptoctx,
2N/A id->reqctx = req_cryptoctx,
2N/A id->idctx = id_cryptoctx;
2N/A id->index = 0;
2N/A *ih_ret = (pkinit_cert_iter_handle) id;
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * End iteration over the certs loaded in crypto_load_certs()
2N/A */
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_cert_iteration_end(krb5_context context,
2N/A pkinit_cert_iter_handle ih)
2N/A{
2N/A struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
2N/A
2N/A if (id == NULL || id->magic != ITER_MAGIC)
2N/A return EINVAL;
2N/A free(ih);
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * Get next certificate handle
2N/A */
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_cert_iteration_next(krb5_context context,
2N/A pkinit_cert_iter_handle ih,
2N/A pkinit_cert_handle *ch_ret)
2N/A{
2N/A struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
2N/A struct _pkinit_cert_data *cd;
2N/A pkinit_identity_crypto_context id_cryptoctx;
2N/A
2N/A if (id == NULL || id->magic != ITER_MAGIC)
2N/A return EINVAL;
2N/A
2N/A if (ch_ret == NULL)
2N/A return EINVAL;
2N/A
2N/A id_cryptoctx = id->idctx;
2N/A if (id_cryptoctx == NULL)
2N/A return EINVAL;
2N/A
2N/A if (id_cryptoctx->creds[id->index] == NULL)
2N/A return PKINIT_ITER_NO_MORE;
2N/A
2N/A cd = calloc(1, sizeof(*cd));
2N/A if (cd == NULL)
2N/A return ENOMEM;
2N/A
2N/A cd->magic = CERT_MAGIC;
2N/A cd->plgctx = id->plgctx;
2N/A cd->reqctx = id->reqctx;
2N/A cd->idctx = id->idctx;
2N/A cd->index = id->index;
2N/A cd->cred = id_cryptoctx->creds[id->index++];
2N/A *ch_ret = (pkinit_cert_handle)cd;
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * Release cert handle
2N/A */
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_cert_release(krb5_context context,
2N/A pkinit_cert_handle ch)
2N/A{
2N/A struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
2N/A if (cd == NULL || cd->magic != CERT_MAGIC)
2N/A return EINVAL;
2N/A free(cd);
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * Get certificate Key Usage and Extended Key Usage
2N/A */
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Acrypto_retieve_X509_key_usage(krb5_context context,
2N/A pkinit_plg_crypto_context plgcctx,
2N/A pkinit_req_crypto_context reqcctx,
2N/A X509 *x,
2N/A unsigned int *ret_ku_bits,
2N/A unsigned int *ret_eku_bits)
2N/A{
2N/A /* Solaris Kerberos */
2N/A int i;
2N/A unsigned int eku_bits = 0, ku_bits = 0;
2N/A ASN1_BIT_STRING *usage = NULL;
2N/A
2N/A if (ret_ku_bits == NULL && ret_eku_bits == NULL)
2N/A return EINVAL;
2N/A
2N/A if (ret_eku_bits)
2N/A *ret_eku_bits = 0;
2N/A else {
2N/A pkiDebug("%s: EKUs not requested, not checking\n", __FUNCTION__);
2N/A goto check_kus;
2N/A }
2N/A
2N/A /* Start with Extended Key usage */
2N/A i = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
2N/A if (i >= 0) {
2N/A EXTENDED_KEY_USAGE *eku;
2N/A
2N/A eku = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL);
2N/A if (eku) {
2N/A for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
2N/A ASN1_OBJECT *certoid;
2N/A certoid = sk_ASN1_OBJECT_value(eku, i);
2N/A if ((OBJ_cmp(certoid, plgcctx->id_pkinit_KPClientAuth)) == 0)
2N/A eku_bits |= PKINIT_EKU_PKINIT;
2N/A else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_ms_smartcard_login))) == 0)
2N/A eku_bits |= PKINIT_EKU_MSSCLOGIN;
2N/A else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_client_auth))) == 0)
2N/A eku_bits |= PKINIT_EKU_CLIENTAUTH;
2N/A else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_email_protect))) == 0)
2N/A eku_bits |= PKINIT_EKU_EMAILPROTECTION;
2N/A }
2N/A EXTENDED_KEY_USAGE_free(eku);
2N/A }
2N/A }
2N/A pkiDebug("%s: returning eku 0x%08x\n", __FUNCTION__, eku_bits);
2N/A *ret_eku_bits = eku_bits;
2N/A
2N/Acheck_kus:
2N/A /* Now the Key Usage bits */
2N/A if (ret_ku_bits)
2N/A *ret_ku_bits = 0;
2N/A else {
2N/A pkiDebug("%s: KUs not requested, not checking\n", __FUNCTION__);
2N/A goto out;
2N/A }
2N/A
2N/A /* Make sure usage exists before checking bits */
2N/A usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL);
2N/A if (usage) {
2N/A if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
2N/A ku_bits |= PKINIT_KU_DIGITALSIGNATURE;
2N/A if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
2N/A ku_bits |= PKINIT_KU_KEYENCIPHERMENT;
2N/A ASN1_BIT_STRING_free(usage);
2N/A }
2N/A
2N/A pkiDebug("%s: returning ku 0x%08x\n", __FUNCTION__, ku_bits);
2N/A *ret_ku_bits = ku_bits;
2N/A
2N/Aout:
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * Return a string format of an X509_NAME in buf where
2N/A * size is an in/out parameter. On input it is the size
2N/A * of the buffer, and on output it is the actual length
2N/A * of the name.
2N/A * If buf is NULL, returns the length req'd to hold name
2N/A */
2N/Astatic char *
2N/AX509_NAME_oneline_ex(X509_NAME * a,
2N/A char *buf,
2N/A unsigned int *size,
2N/A unsigned long flag)
2N/A{
2N/A BIO *out = NULL;
2N/A
2N/A out = BIO_new(BIO_s_mem ());
2N/A if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
2N/A if (buf != NULL && *size > (int) BIO_number_written(out)) {
2N/A (void) memset(buf, 0, *size);
2N/A BIO_read(out, buf, (int) BIO_number_written(out));
2N/A }
2N/A else {
2N/A *size = BIO_number_written(out);
2N/A }
2N/A }
2N/A BIO_free(out);
2N/A return (buf);
2N/A}
2N/A
2N/A/*
2N/A * Get certificate information
2N/A */
2N/Akrb5_error_code
2N/Acrypto_cert_get_matching_data(krb5_context context,
2N/A pkinit_cert_handle ch,
2N/A pkinit_cert_matching_data **ret_md)
2N/A{
2N/A krb5_error_code retval;
2N/A pkinit_cert_matching_data *md;
2N/A krb5_principal *pkinit_sans =NULL, *upn_sans = NULL;
2N/A struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
2N/A int i, j;
2N/A char buf[DN_BUF_LEN];
2N/A unsigned int bufsize = sizeof(buf);
2N/A
2N/A if (cd == NULL || cd->magic != CERT_MAGIC)
2N/A return EINVAL;
2N/A if (ret_md == NULL)
2N/A return EINVAL;
2N/A
2N/A md = calloc(1, sizeof(*md));
2N/A if (md == NULL)
2N/A return ENOMEM;
2N/A
2N/A md->ch = ch;
2N/A
2N/A /* get the subject name (in rfc2253 format) */
2N/A X509_NAME_oneline_ex(X509_get_subject_name(cd->cred->cert),
2N/A buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
2N/A md->subject_dn = strdup(buf);
2N/A if (md->subject_dn == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* get the issuer name (in rfc2253 format) */
2N/A X509_NAME_oneline_ex(X509_get_issuer_name(cd->cred->cert),
2N/A buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
2N/A md->issuer_dn = strdup(buf);
2N/A if (md->issuer_dn == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* get the san data */
2N/A retval = crypto_retrieve_X509_sans(context, cd->plgctx, cd->reqctx,
2N/A cd->cred->cert, &pkinit_sans,
2N/A &upn_sans, NULL);
2N/A if (retval)
2N/A goto cleanup;
2N/A
2N/A j = 0;
2N/A if (pkinit_sans != NULL) {
2N/A for (i = 0; pkinit_sans[i] != NULL; i++)
2N/A j++;
2N/A }
2N/A if (upn_sans != NULL) {
2N/A for (i = 0; upn_sans[i] != NULL; i++)
2N/A j++;
2N/A }
2N/A if (j != 0) {
2N/A md->sans = calloc((size_t)j+1, sizeof(*md->sans));
2N/A if (md->sans == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A j = 0;
2N/A if (pkinit_sans != NULL) {
2N/A for (i = 0; pkinit_sans[i] != NULL; i++)
2N/A md->sans[j++] = pkinit_sans[i];
2N/A free(pkinit_sans);
2N/A }
2N/A if (upn_sans != NULL) {
2N/A for (i = 0; upn_sans[i] != NULL; i++)
2N/A md->sans[j++] = upn_sans[i];
2N/A free(upn_sans);
2N/A }
2N/A md->sans[j] = NULL;
2N/A } else
2N/A md->sans = NULL;
2N/A
2N/A /* get the KU and EKU data */
2N/A
2N/A retval = crypto_retieve_X509_key_usage(context, cd->plgctx, cd->reqctx,
2N/A cd->cred->cert,
2N/A &md->ku_bits, &md->eku_bits);
2N/A if (retval)
2N/A goto cleanup;
2N/A
2N/A *ret_md = md;
2N/A retval = 0;
2N/Acleanup:
2N/A if (retval) {
2N/A if (md)
2N/A crypto_cert_free_matching_data(context, md);
2N/A }
2N/A return retval;
2N/A}
2N/A
2N/A/*
2N/A * Free certificate information
2N/A */
2N/Akrb5_error_code
2N/Acrypto_cert_free_matching_data(krb5_context context,
2N/A pkinit_cert_matching_data *md)
2N/A{
2N/A krb5_principal p;
2N/A int i;
2N/A
2N/A if (md == NULL)
2N/A return EINVAL;
2N/A if (md->subject_dn)
2N/A free(md->subject_dn);
2N/A if (md->issuer_dn)
2N/A free(md->issuer_dn);
2N/A if (md->sans) {
2N/A for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i])
2N/A krb5_free_principal(context, p);
2N/A free(md->sans);
2N/A }
2N/A free(md);
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * Make this matching certificate "the chosen one"
2N/A */
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_cert_select(krb5_context context,
2N/A pkinit_cert_matching_data *md)
2N/A{
2N/A struct _pkinit_cert_data *cd;
2N/A if (md == NULL)
2N/A return EINVAL;
2N/A
2N/A cd = (struct _pkinit_cert_data *)md->ch;
2N/A if (cd == NULL || cd->magic != CERT_MAGIC)
2N/A return EINVAL;
2N/A
2N/A /* copy the selected cert into our id_cryptoctx */
2N/A if (cd->idctx->my_certs != NULL) {
2N/A sk_X509_pop_free(cd->idctx->my_certs, X509_free);
2N/A }
2N/A cd->idctx->my_certs = sk_X509_new_null();
2N/A sk_X509_push(cd->idctx->my_certs, cd->cred->cert);
2N/A cd->idctx->creds[cd->index]->cert = NULL; /* Don't free it twice */
2N/A cd->idctx->cert_index = 0;
2N/A
2N/A if (cd->idctx->pkcs11_method != 1) {
2N/A cd->idctx->my_key = cd->cred->key;
2N/A cd->idctx->creds[cd->index]->key = NULL; /* Don't free it twice */
2N/A }
2N/A#ifndef WITHOUT_PKCS11
2N/A else {
2N/A cd->idctx->cert_id = cd->cred->cert_id;
2N/A cd->idctx->creds[cd->index]->cert_id = NULL; /* Don't free it twice */
2N/A cd->idctx->cert_id_len = cd->cred->cert_id_len;
2N/A }
2N/A#endif
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * Choose the default certificate as "the chosen one"
2N/A */
2N/Akrb5_error_code
2N/Acrypto_cert_select_default(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx)
2N/A{
2N/A krb5_error_code retval;
2N/A int cert_count = 0;
2N/A
2N/A retval = crypto_cert_get_count(context, plg_cryptoctx, req_cryptoctx,
2N/A id_cryptoctx, &cert_count);
2N/A if (retval) {
2N/A pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
2N/A __FUNCTION__, retval, error_message(retval));
2N/A goto errout;
2N/A }
2N/A if (cert_count != 1) {
2N/A /* Solaris Kerberos: Improved error messages */
2N/A retval = EINVAL;
2N/A krb5_set_error_message(context, retval,
2N/A gettext("Failed to select default certificate: "
2N/A "found %d certs to choose from but there must be exactly one"),
2N/A cert_count);
2N/A pkiDebug("%s: ERROR: There are %d certs to choose from, "
2N/A "but there must be exactly one.\n",
2N/A __FUNCTION__, cert_count);
2N/A goto errout;
2N/A }
2N/A /* copy the selected cert into our id_cryptoctx */
2N/A if (id_cryptoctx->my_certs != NULL) {
2N/A sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
2N/A }
2N/A id_cryptoctx->my_certs = sk_X509_new_null();
2N/A sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
2N/A id_cryptoctx->creds[0]->cert = NULL; /* Don't free it twice */
2N/A id_cryptoctx->cert_index = 0;
2N/A
2N/A if (id_cryptoctx->pkcs11_method != 1) {
2N/A id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
2N/A id_cryptoctx->creds[0]->key = NULL; /* Don't free it twice */
2N/A }
2N/A#ifndef WITHOUT_PKCS11
2N/A else {
2N/A id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
2N/A id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
2N/A id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
2N/A }
2N/A#endif
2N/A retval = 0;
2N/Aerrout:
2N/A return retval;
2N/A}
2N/A
2N/A
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Aload_cas_and_crls(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A int catype,
2N/A char *filename)
2N/A{
2N/A STACK_OF(X509_INFO) *sk = NULL;
2N/A STACK_OF(X509) *ca_certs = NULL;
2N/A STACK_OF(X509_CRL) *ca_crls = NULL;
2N/A BIO *in = NULL;
2N/A /* Solaris Kerberos */
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A int i = 0;
2N/A
2N/A /* If there isn't already a stack in the context,
2N/A * create a temporary one now */
2N/A switch(catype) {
2N/A case CATYPE_ANCHORS:
2N/A if (id_cryptoctx->trustedCAs != NULL)
2N/A ca_certs = id_cryptoctx->trustedCAs;
2N/A else {
2N/A ca_certs = sk_X509_new_null();
2N/A if (ca_certs == NULL)
2N/A return ENOMEM;
2N/A }
2N/A break;
2N/A case CATYPE_INTERMEDIATES:
2N/A if (id_cryptoctx->intermediateCAs != NULL)
2N/A ca_certs = id_cryptoctx->intermediateCAs;
2N/A else {
2N/A ca_certs = sk_X509_new_null();
2N/A if (ca_certs == NULL)
2N/A return ENOMEM;
2N/A }
2N/A break;
2N/A case CATYPE_CRLS:
2N/A if (id_cryptoctx->revoked != NULL)
2N/A ca_crls = id_cryptoctx->revoked;
2N/A else {
2N/A ca_crls = sk_X509_CRL_new_null();
2N/A if (ca_crls == NULL)
2N/A return ENOMEM;
2N/A }
2N/A break;
2N/A default:
2N/A return ENOTSUP;
2N/A }
2N/A
2N/A if (!(in = BIO_new_file(filename, "r"))) {
2N/A retval = errno;
2N/A pkiDebug("%s: error opening file '%s': %s\n", __FUNCTION__,
2N/A filename, error_message(errno));
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* This loads from a file, a stack of x509/crl/pkey sets */
2N/A if ((sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) {
2N/A pkiDebug("%s: error reading file '%s'\n", __FUNCTION__, filename);
2N/A retval = EIO;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* scan over the stack created from loading the file contents,
2N/A * weed out duplicates, and push new ones onto the return stack
2N/A */
2N/A for (i = 0; i < sk_X509_INFO_num(sk); i++) {
2N/A X509_INFO *xi = sk_X509_INFO_value(sk, i);
2N/A if (xi != NULL && xi->x509 != NULL && catype != CATYPE_CRLS) {
2N/A int j = 0, size = sk_X509_num(ca_certs), flag = 0;
2N/A
2N/A if (!size) {
2N/A sk_X509_push(ca_certs, xi->x509);
2N/A xi->x509 = NULL;
2N/A continue;
2N/A }
2N/A for (j = 0; j < size; j++) {
2N/A X509 *x = sk_X509_value(ca_certs, j);
2N/A flag = X509_cmp(x, xi->x509);
2N/A if (flag == 0)
2N/A break;
2N/A else
2N/A continue;
2N/A }
2N/A if (flag != 0) {
2N/A sk_X509_push(ca_certs, X509_dup(xi->x509));
2N/A }
2N/A } else if (xi != NULL && xi->crl != NULL && catype == CATYPE_CRLS) {
2N/A int j = 0, size = sk_X509_CRL_num(ca_crls), flag = 0;
2N/A if (!size) {
2N/A sk_X509_CRL_push(ca_crls, xi->crl);
2N/A xi->crl = NULL;
2N/A continue;
2N/A }
2N/A for (j = 0; j < size; j++) {
2N/A X509_CRL *x = sk_X509_CRL_value(ca_crls, j);
2N/A flag = X509_CRL_cmp(x, xi->crl);
2N/A if (flag == 0)
2N/A break;
2N/A else
2N/A continue;
2N/A }
2N/A if (flag != 0) {
2N/A sk_X509_CRL_push(ca_crls, X509_CRL_dup(xi->crl));
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* If we added something and there wasn't a stack in the
2N/A * context before, add the temporary stack to the context.
2N/A */
2N/A switch(catype) {
2N/A case CATYPE_ANCHORS:
2N/A if (sk_X509_num(ca_certs) == 0) {
2N/A pkiDebug("no anchors in file, %s\n", filename);
2N/A if (id_cryptoctx->trustedCAs == NULL)
2N/A sk_X509_free(ca_certs);
2N/A } else {
2N/A if (id_cryptoctx->trustedCAs == NULL)
2N/A id_cryptoctx->trustedCAs = ca_certs;
2N/A }
2N/A break;
2N/A case CATYPE_INTERMEDIATES:
2N/A if (sk_X509_num(ca_certs) == 0) {
2N/A pkiDebug("no intermediates in file, %s\n", filename);
2N/A if (id_cryptoctx->intermediateCAs == NULL)
2N/A sk_X509_free(ca_certs);
2N/A } else {
2N/A if (id_cryptoctx->intermediateCAs == NULL)
2N/A id_cryptoctx->intermediateCAs = ca_certs;
2N/A }
2N/A break;
2N/A case CATYPE_CRLS:
2N/A if (sk_X509_CRL_num(ca_crls) == 0) {
2N/A pkiDebug("no crls in file, %s\n", filename);
2N/A if (id_cryptoctx->revoked == NULL)
2N/A sk_X509_CRL_free(ca_crls);
2N/A } else {
2N/A if (id_cryptoctx->revoked == NULL)
2N/A id_cryptoctx->revoked = ca_crls;
2N/A }
2N/A break;
2N/A default:
2N/A /* Should have been caught above! */
2N/A retval = EINVAL;
2N/A goto cleanup;
2N/A /* Solaris Kerberos: removed "break" as it's never reached */
2N/A }
2N/A
2N/A retval = 0;
2N/A
2N/A cleanup:
2N/A if (in != NULL)
2N/A BIO_free(in);
2N/A if (sk != NULL)
2N/A sk_X509_INFO_pop_free(sk, X509_INFO_free);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Aload_cas_and_crls_dir(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A int catype,
2N/A char *dirname)
2N/A{
2N/A krb5_error_code retval = EINVAL;
2N/A DIR *d = NULL;
2N/A struct dirent *dentry = NULL;
2N/A char filename[1024];
2N/A
2N/A if (dirname == NULL)
2N/A return EINVAL;
2N/A
2N/A d = opendir(dirname);
2N/A if (d == NULL)
2N/A return ENOENT;
2N/A
2N/A while ((dentry = readdir(d))) {
2N/A if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(filename)) {
2N/A pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
2N/A __FUNCTION__, dirname, dentry->d_name);
2N/A goto cleanup;
2N/A }
2N/A /* Ignore subdirectories and anything starting with a dot */
2N/A#ifdef DT_DIR
2N/A if (dentry->d_type == DT_DIR)
2N/A continue;
2N/A#endif
2N/A if (dentry->d_name[0] == '.')
2N/A continue;
2N/A (void) snprintf(filename, sizeof(filename), "%s/%s", dirname, dentry->d_name);
2N/A
2N/A retval = load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
2N/A id_cryptoctx, catype, filename);
2N/A if (retval)
2N/A goto cleanup;
2N/A }
2N/A
2N/A retval = 0;
2N/A
2N/A cleanup:
2N/A if (d != NULL)
2N/A (void) closedir(d);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acrypto_load_cas_and_crls(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_opts *idopts,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A int idtype,
2N/A int catype,
2N/A char *id)
2N/A{
2N/A pkiDebug("%s: called with idtype %s and catype %s\n",
2N/A __FUNCTION__, idtype2string(idtype), catype2string(catype));
2N/A /* Solaris Kerberos: Removed "break"'s as they are never reached */
2N/A switch (idtype) {
2N/A case IDTYPE_FILE:
2N/A return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
2N/A id_cryptoctx, catype, id);
2N/A case IDTYPE_DIR:
2N/A return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
2N/A id_cryptoctx, catype, id);
2N/A default:
2N/A return ENOTSUP;
2N/A }
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Acreate_identifiers_from_stack(STACK_OF(X509) *sk,
2N/A krb5_external_principal_identifier *** ids)
2N/A{
2N/A krb5_error_code retval = ENOMEM;
2N/A int i = 0, sk_size = sk_X509_num(sk);
2N/A krb5_external_principal_identifier **krb5_cas = NULL;
2N/A X509 *x = NULL;
2N/A X509_NAME *xn = NULL;
2N/A unsigned char *p = NULL;
2N/A int len = 0;
2N/A PKCS7_ISSUER_AND_SERIAL *is = NULL;
2N/A char buf[DN_BUF_LEN];
2N/A
2N/A *ids = NULL;
2N/A
2N/A krb5_cas =
2N/A malloc((sk_size + 1) * sizeof(krb5_external_principal_identifier *));
2N/A if (krb5_cas == NULL)
2N/A return ENOMEM;
2N/A krb5_cas[sk_size] = NULL;
2N/A
2N/A for (i = 0; i < sk_size; i++) {
2N/A krb5_cas[i] = (krb5_external_principal_identifier *)malloc(sizeof(krb5_external_principal_identifier));
2N/A
2N/A x = sk_X509_value(sk, i);
2N/A
2N/A X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
2N/A pkiDebug("#%d cert= %s\n", i, buf);
2N/A
2N/A /* fill-in subjectName */
2N/A krb5_cas[i]->subjectName.magic = 0;
2N/A krb5_cas[i]->subjectName.length = 0;
2N/A krb5_cas[i]->subjectName.data = NULL;
2N/A
2N/A xn = X509_get_subject_name(x);
2N/A len = i2d_X509_NAME(xn, NULL);
2N/A if ((p = krb5_cas[i]->subjectName.data = (unsigned char *)malloc((size_t) len)) == NULL)
2N/A goto cleanup;
2N/A i2d_X509_NAME(xn, &p);
2N/A krb5_cas[i]->subjectName.length = len;
2N/A
2N/A /* fill-in issuerAndSerialNumber */
2N/A krb5_cas[i]->issuerAndSerialNumber.length = 0;
2N/A krb5_cas[i]->issuerAndSerialNumber.magic = 0;
2N/A krb5_cas[i]->issuerAndSerialNumber.data = NULL;
2N/A
2N/A#ifdef LONGHORN_BETA_COMPAT
2N/Aif (longhorn == 0) { /* XXX Longhorn doesn't like this */
2N/A#endif
2N/A is = PKCS7_ISSUER_AND_SERIAL_new();
2N/A X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
2N/A M_ASN1_INTEGER_free(is->serial);
2N/A is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
2N/A len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
2N/A if ((p = krb5_cas[i]->issuerAndSerialNumber.data =
2N/A (unsigned char *)malloc((size_t) len)) == NULL)
2N/A goto cleanup;
2N/A i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
2N/A krb5_cas[i]->issuerAndSerialNumber.length = len;
2N/A#ifdef LONGHORN_BETA_COMPAT
2N/A}
2N/A#endif
2N/A
2N/A /* fill-in subjectKeyIdentifier */
2N/A krb5_cas[i]->subjectKeyIdentifier.length = 0;
2N/A krb5_cas[i]->subjectKeyIdentifier.magic = 0;
2N/A krb5_cas[i]->subjectKeyIdentifier.data = NULL;
2N/A
2N/A
2N/A#ifdef LONGHORN_BETA_COMPAT
2N/Aif (longhorn == 0) { /* XXX Longhorn doesn't like this */
2N/A#endif
2N/A if (X509_get_ext_by_NID(x, NID_subject_key_identifier, -1) >= 0) {
2N/A ASN1_OCTET_STRING *ikeyid = NULL;
2N/A
2N/A if ((ikeyid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL,
2N/A NULL))) {
2N/A len = i2d_ASN1_OCTET_STRING(ikeyid, NULL);
2N/A if ((p = krb5_cas[i]->subjectKeyIdentifier.data =
2N/A (unsigned char *)malloc((size_t) len)) == NULL)
2N/A goto cleanup;
2N/A i2d_ASN1_OCTET_STRING(ikeyid, &p);
2N/A krb5_cas[i]->subjectKeyIdentifier.length = len;
2N/A }
2N/A if (ikeyid != NULL)
2N/A ASN1_OCTET_STRING_free(ikeyid);
2N/A }
2N/A#ifdef LONGHORN_BETA_COMPAT
2N/A}
2N/A#endif
2N/A if (is != NULL) {
2N/A if (is->issuer != NULL)
2N/A X509_NAME_free(is->issuer);
2N/A if (is->serial != NULL)
2N/A ASN1_INTEGER_free(is->serial);
2N/A free(is);
2N/A }
2N/A }
2N/A
2N/A *ids = krb5_cas;
2N/A
2N/A retval = 0;
2N/A cleanup:
2N/A if (retval)
2N/A free_krb5_external_principal_identifier(&krb5_cas);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic krb5_error_code
2N/Acreate_krb5_invalidCertificates(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_external_principal_identifier *** ids)
2N/A{
2N/A
2N/A krb5_error_code retval = ENOMEM;
2N/A STACK_OF(X509) *sk = NULL;
2N/A
2N/A *ids = NULL;
2N/A if (req_cryptoctx->received_cert == NULL)
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A
2N/A sk = sk_X509_new_null();
2N/A if (sk == NULL)
2N/A goto cleanup;
2N/A sk_X509_push(sk, req_cryptoctx->received_cert);
2N/A
2N/A retval = create_identifiers_from_stack(sk, ids);
2N/A
2N/A sk_X509_free(sk);
2N/Acleanup:
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acreate_krb5_supportedCMSTypes(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_algorithm_identifier ***oids)
2N/A{
2N/A
2N/A krb5_error_code retval = ENOMEM;
2N/A krb5_algorithm_identifier **loids = NULL;
2N/A krb5_octet_data des3oid = {0, 8, (unsigned char *)"\x2A\x86\x48\x86\xF7\x0D\x03\x07" };
2N/A
2N/A *oids = NULL;
2N/A loids = malloc(2 * sizeof(krb5_algorithm_identifier *));
2N/A if (loids == NULL)
2N/A goto cleanup;
2N/A loids[1] = NULL;
2N/A loids[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2N/A if (loids[0] == NULL) {
2N/A free(loids);
2N/A goto cleanup;
2N/A }
2N/A retval = pkinit_copy_krb5_octet_data(&loids[0]->algorithm, &des3oid);
2N/A if (retval) {
2N/A free(loids[0]);
2N/A free(loids);
2N/A goto cleanup;
2N/A }
2N/A loids[0]->parameters.length = 0;
2N/A loids[0]->parameters.data = NULL;
2N/A
2N/A *oids = loids;
2N/A retval = 0;
2N/Acleanup:
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acreate_krb5_trustedCertifiers(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_external_principal_identifier *** ids)
2N/A{
2N/A
2N/A /* Solaris Kerberos */
2N/A STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
2N/A
2N/A *ids = NULL;
2N/A if (id_cryptoctx->trustedCAs == NULL)
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A
2N/A return create_identifiers_from_stack(sk, ids);
2N/A
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acreate_krb5_trustedCas(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A int flag,
2N/A krb5_trusted_ca *** ids)
2N/A{
2N/A krb5_error_code retval = ENOMEM;
2N/A STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
2N/A int i = 0, len = 0, sk_size = sk_X509_num(sk);
2N/A krb5_trusted_ca **krb5_cas = NULL;
2N/A X509 *x = NULL;
2N/A char buf[DN_BUF_LEN];
2N/A X509_NAME *xn = NULL;
2N/A unsigned char *p = NULL;
2N/A PKCS7_ISSUER_AND_SERIAL *is = NULL;
2N/A
2N/A *ids = NULL;
2N/A if (id_cryptoctx->trustedCAs == NULL)
2N/A return KRB5KDC_ERR_PREAUTH_FAILED;
2N/A
2N/A krb5_cas = malloc((sk_size + 1) * sizeof(krb5_trusted_ca *));
2N/A if (krb5_cas == NULL)
2N/A return ENOMEM;
2N/A krb5_cas[sk_size] = NULL;
2N/A
2N/A for (i = 0; i < sk_size; i++) {
2N/A krb5_cas[i] = (krb5_trusted_ca *)malloc(sizeof(krb5_trusted_ca));
2N/A if (krb5_cas[i] == NULL)
2N/A goto cleanup;
2N/A x = sk_X509_value(sk, i);
2N/A
2N/A X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
2N/A pkiDebug("#%d cert= %s\n", i, buf);
2N/A
2N/A switch (flag) {
2N/A case choice_trusted_cas_principalName:
2N/A krb5_cas[i]->choice = choice_trusted_cas_principalName;
2N/A break;
2N/A case choice_trusted_cas_caName:
2N/A krb5_cas[i]->choice = choice_trusted_cas_caName;
2N/A krb5_cas[i]->u.caName.data = NULL;
2N/A krb5_cas[i]->u.caName.length = 0;
2N/A xn = X509_get_subject_name(x);
2N/A len = i2d_X509_NAME(xn, NULL);
2N/A if ((p = krb5_cas[i]->u.caName.data =
2N/A (unsigned char *)malloc((size_t) len)) == NULL)
2N/A goto cleanup;
2N/A i2d_X509_NAME(xn, &p);
2N/A krb5_cas[i]->u.caName.length = len;
2N/A break;
2N/A case choice_trusted_cas_issuerAndSerial:
2N/A krb5_cas[i]->choice = choice_trusted_cas_issuerAndSerial;
2N/A krb5_cas[i]->u.issuerAndSerial.data = NULL;
2N/A krb5_cas[i]->u.issuerAndSerial.length = 0;
2N/A is = PKCS7_ISSUER_AND_SERIAL_new();
2N/A X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
2N/A M_ASN1_INTEGER_free(is->serial);
2N/A is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
2N/A len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
2N/A if ((p = krb5_cas[i]->u.issuerAndSerial.data =
2N/A (unsigned char *)malloc((size_t) len)) == NULL)
2N/A goto cleanup;
2N/A i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
2N/A krb5_cas[i]->u.issuerAndSerial.length = len;
2N/A if (is != NULL) {
2N/A if (is->issuer != NULL)
2N/A X509_NAME_free(is->issuer);
2N/A if (is->serial != NULL)
2N/A ASN1_INTEGER_free(is->serial);
2N/A free(is);
2N/A }
2N/A break;
2N/A default: break;
2N/A }
2N/A }
2N/A retval = 0;
2N/A *ids = krb5_cas;
2N/Acleanup:
2N/A if (retval)
2N/A free_krb5_trusted_ca(&krb5_cas);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Akrb5_error_code
2N/Acreate_issuerAndSerial(krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A unsigned char **out,
2N/A unsigned int *out_len)
2N/A{
2N/A unsigned char *p = NULL;
2N/A PKCS7_ISSUER_AND_SERIAL *is = NULL;
2N/A int len = 0;
2N/A krb5_error_code retval = ENOMEM;
2N/A X509 *cert = req_cryptoctx->received_cert;
2N/A
2N/A *out = NULL;
2N/A *out_len = 0;
2N/A if (req_cryptoctx->received_cert == NULL)
2N/A return 0;
2N/A
2N/A is = PKCS7_ISSUER_AND_SERIAL_new();
2N/A X509_NAME_set(&is->issuer, X509_get_issuer_name(cert));
2N/A M_ASN1_INTEGER_free(is->serial);
2N/A is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(cert));
2N/A len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
2N/A if ((p = *out = (unsigned char *)malloc((size_t) len)) == NULL)
2N/A goto cleanup;
2N/A i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
2N/A *out_len = len;
2N/A retval = 0;
2N/A
2N/Acleanup:
2N/A X509_NAME_free(is->issuer);
2N/A ASN1_INTEGER_free(is->serial);
2N/A free(is);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Astatic int
2N/Apkcs7_decrypt(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A PKCS7 *p7,
2N/A BIO *data)
2N/A{
2N/A BIO *tmpmem = NULL;
2N/A /* Solaris Kerberos */
2N/A int i = 0;
2N/A char buf[4096];
2N/A
2N/A if(p7 == NULL)
2N/A return 0;
2N/A
2N/A if(!PKCS7_type_is_enveloped(p7)) {
2N/A pkiDebug("wrong pkcs7 content type\n");
2N/A return 0;
2N/A }
2N/A
2N/A if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) {
2N/A pkiDebug("unable to decrypt pkcs7 object\n");
2N/A return 0;
2N/A }
2N/A/* Solaris Kerberos: Suppress sun studio compiler warning */
2N/A#pragma error_messages (off, E_END_OF_LOOP_CODE_NOT_REACHED)
2N/A for(;;) {
2N/A i = BIO_read(tmpmem, buf, sizeof(buf));
2N/A if (i <= 0) break;
2N/A BIO_write(data, buf, i);
2N/A BIO_free_all(tmpmem);
2N/A return 1;
2N/A }
2N/A#pragma error_messages (default, E_END_OF_LOOP_CODE_NOT_REACHED)
2N/A
2N/A return 0;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Apkinit_process_td_trusted_certifiers(
2N/A krb5_context context,
2N/A pkinit_plg_crypto_context plg_cryptoctx,
2N/A pkinit_req_crypto_context req_cryptoctx,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A krb5_external_principal_identifier **krb5_trusted_certifiers,
2N/A int td_type)
2N/A{
2N/A krb5_error_code retval = ENOMEM;
2N/A STACK_OF(X509_NAME) *sk_xn = NULL;
2N/A X509_NAME *xn = NULL;
2N/A PKCS7_ISSUER_AND_SERIAL *is = NULL;
2N/A ASN1_OCTET_STRING *id = NULL;
2N/A const unsigned char *p = NULL;
2N/A char buf[DN_BUF_LEN];
2N/A int i = 0;
2N/A
2N/A if (td_type == TD_TRUSTED_CERTIFIERS)
2N/A pkiDebug("received trusted certifiers\n");
2N/A else
2N/A pkiDebug("received invalid certificate\n");
2N/A
2N/A sk_xn = sk_X509_NAME_new_null();
2N/A while(krb5_trusted_certifiers[i] != NULL) {
2N/A if (krb5_trusted_certifiers[i]->subjectName.data != NULL) {
2N/A p = krb5_trusted_certifiers[i]->subjectName.data;
2N/A xn = d2i_X509_NAME(NULL, &p,
2N/A (int)krb5_trusted_certifiers[i]->subjectName.length);
2N/A if (xn == NULL)
2N/A goto cleanup;
2N/A X509_NAME_oneline(xn, buf, sizeof(buf));
2N/A if (td_type == TD_TRUSTED_CERTIFIERS)
2N/A pkiDebug("#%d cert = %s is trusted by kdc\n", i, buf);
2N/A else
2N/A pkiDebug("#%d cert = %s is invalid\n", i, buf);
2N/A sk_X509_NAME_push(sk_xn, xn);
2N/A }
2N/A
2N/A if (krb5_trusted_certifiers[i]->issuerAndSerialNumber.data != NULL) {
2N/A p = krb5_trusted_certifiers[i]->issuerAndSerialNumber.data;
2N/A is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p,
2N/A (int)krb5_trusted_certifiers[i]->issuerAndSerialNumber.length);
2N/A if (is == NULL)
2N/A goto cleanup;
2N/A X509_NAME_oneline(is->issuer, buf, sizeof(buf));
2N/A if (td_type == TD_TRUSTED_CERTIFIERS)
2N/A pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
2N/A buf, ASN1_INTEGER_get(is->serial));
2N/A else
2N/A pkiDebug("#%d issuer = %s serial = %ld is invalid\n", i, buf,
2N/A ASN1_INTEGER_get(is->serial));
2N/A PKCS7_ISSUER_AND_SERIAL_free(is);
2N/A }
2N/A
2N/A if (krb5_trusted_certifiers[i]->subjectKeyIdentifier.data != NULL) {
2N/A p = krb5_trusted_certifiers[i]->subjectKeyIdentifier.data;
2N/A id = d2i_ASN1_OCTET_STRING(NULL, &p,
2N/A (int)krb5_trusted_certifiers[i]->subjectKeyIdentifier.length);
2N/A if (id == NULL)
2N/A goto cleanup;
2N/A /* XXX */
2N/A ASN1_OCTET_STRING_free(id);
2N/A }
2N/A i++;
2N/A }
2N/A /* XXX Since we not doing anything with received trusted certifiers
2N/A * return an error. this is the place where we can pick a different
2N/A * client certificate based on the information in td_trusted_certifiers
2N/A */
2N/A retval = KRB5KDC_ERR_PREAUTH_FAILED;
2N/Acleanup:
2N/A if (sk_xn != NULL)
2N/A sk_X509_NAME_pop_free(sk_xn, X509_NAME_free);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Astatic BIO *
2N/Apkcs7_dataDecode(krb5_context context,
2N/A pkinit_identity_crypto_context id_cryptoctx,
2N/A PKCS7 *p7)
2N/A{
2N/A int i = 0;
2N/A unsigned int jj = 0, tmp_len = 0;
2N/A BIO *out=NULL,*etmp=NULL,*bio=NULL;
2N/A unsigned char *tmp=NULL;
2N/A ASN1_OCTET_STRING *data_body=NULL;
2N/A const EVP_CIPHER *evp_cipher=NULL;
2N/A EVP_CIPHER_CTX *evp_ctx=NULL;
2N/A X509_ALGOR *enc_alg=NULL;
2N/A STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
2N/A/* Solaris Kerberos: Not used */
2N/A#if 0
2N/A X509_ALGOR *xalg=NULL;
2N/A#endif
2N/A PKCS7_RECIP_INFO *ri=NULL;
2N/A X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
2N/A id_cryptoctx->cert_index);
2N/A
2N/A p7->state=PKCS7_S_HEADER;
2N/A
2N/A rsk=p7->d.enveloped->recipientinfo;
2N/A enc_alg=p7->d.enveloped->enc_data->algorithm;
2N/A data_body=p7->d.enveloped->enc_data->enc_data;
2N/A evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
2N/A if (evp_cipher == NULL) {
2N/A PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
2N/A goto cleanup;
2N/A }
2N/A/* Solaris Kerberos: Not used */
2N/A#if 0
2N/A xalg=p7->d.enveloped->enc_data->algorithm;
2N/A#endif
2N/A
2N/A if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
2N/A PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* It was encrypted, we need to decrypt the secret key
2N/A * with the private key */
2N/A
2N/A /* Find the recipientInfo which matches the passed certificate
2N/A * (if any)
2N/A */
2N/A
2N/A if (cert) {
2N/A for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
2N/A int tmp_ret = 0;
2N/A ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
2N/A tmp_ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
2N/A cert->cert_info->issuer);
2N/A if (!tmp_ret) {
2N/A tmp_ret = M_ASN1_INTEGER_cmp(cert->cert_info->serialNumber,
2N/A ri->issuer_and_serial->serial);
2N/A if (!tmp_ret)
2N/A break;
2N/A }
2N/A ri=NULL;
2N/A }
2N/A if (ri == NULL) {
2N/A PKCS7err(PKCS7_F_PKCS7_DATADECODE,
2N/A PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
2N/A goto cleanup;
2N/A }
2N/A
2N/A }
2N/A
2N/A /* If we haven't got a certificate try each ri in turn */
2N/A
2N/A if (cert == NULL) {
2N/A for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
2N/A ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
2N/A jj = pkinit_decode_data(context, id_cryptoctx,
2N/A M_ASN1_STRING_data(ri->enc_key),
2N/A (unsigned int) M_ASN1_STRING_length(ri->enc_key),
2N/A &tmp, &tmp_len);
2N/A if (jj) {
2N/A PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (!jj && tmp_len > 0) {
2N/A jj = tmp_len;
2N/A break;
2N/A }
2N/A
2N/A ERR_clear_error();
2N/A ri = NULL;
2N/A }
2N/A
2N/A if (ri == NULL) {
2N/A PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_KEY);
2N/A goto cleanup;
2N/A }
2N/A }
2N/A else {
2N/A jj = pkinit_decode_data(context, id_cryptoctx,
2N/A M_ASN1_STRING_data(ri->enc_key),
2N/A (unsigned int) M_ASN1_STRING_length(ri->enc_key),
2N/A &tmp, &tmp_len);
2N/A /* Solaris Kerberos: tmp_len is unsigned. Cannot be < 0 */
2N/A if (jj || tmp_len == 0) {
2N/A PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
2N/A goto cleanup;
2N/A }
2N/A jj = tmp_len;
2N/A }
2N/A
2N/A evp_ctx=NULL;
2N/A BIO_get_cipher_ctx(etmp,&evp_ctx);
2N/A if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
2N/A goto cleanup;
2N/A if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
2N/A goto cleanup;
2N/A
2N/A if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
2N/A /* Some S/MIME clients don't use the same key
2N/A * and effective key length. The key length is
2N/A * determined by the size of the decrypted RSA key.
2N/A */
2N/A if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)jj)) {
2N/A PKCS7err(PKCS7_F_PKCS7_DATADECODE,
2N/A PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH);
2N/A goto cleanup;
2N/A }
2N/A }
2N/A if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
2N/A goto cleanup;
2N/A
2N/A OPENSSL_cleanse(tmp,jj);
2N/A
2N/A if (out == NULL)
2N/A out=etmp;
2N/A else
2N/A BIO_push(out,etmp);
2N/A etmp=NULL;
2N/A
2N/A if (data_body->length > 0)
2N/A bio = BIO_new_mem_buf(data_body->data, data_body->length);
2N/A else {
2N/A bio=BIO_new(BIO_s_mem());
2N/A BIO_set_mem_eof_return(bio,0);
2N/A }
2N/A BIO_push(out,bio);
2N/A bio=NULL;
2N/A
2N/A /* Solaris Kerberos */
2N/A goto out;
2N/A
2N/Acleanup:
2N/A if (out != NULL) BIO_free_all(out);
2N/A if (etmp != NULL) BIO_free_all(etmp);
2N/A if (bio != NULL) BIO_free_all(bio);
2N/A out=NULL;
2N/A
2N/Aout:
2N/A if (tmp != NULL)
2N/A free(tmp);
2N/A
2N/A return(out);
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Ader_decode_data(unsigned char *data, long data_len,
2N/A unsigned char **out, long *out_len)
2N/A{
2N/A /* Solaris Kerberos */
2N/A krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2N/A ASN1_OCTET_STRING *s = NULL;
2N/A const unsigned char *p = data;
2N/A
2N/A if ((s = d2i_ASN1_BIT_STRING(NULL, &p, data_len)) == NULL)
2N/A goto cleanup;
2N/A *out_len = s->length;
2N/A if ((*out = (unsigned char *) malloc((size_t) *out_len + 1)) == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A (void) memcpy(*out, s->data, (size_t) s->length);
2N/A (*out)[s->length] = '\0';
2N/A
2N/A retval = 0;
2N/A cleanup:
2N/A if (s != NULL)
2N/A ASN1_OCTET_STRING_free(s);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A
2N/A#ifdef DEBUG_DH
2N/Astatic void
2N/Aprint_dh(DH * dh, char *msg)
2N/A{
2N/A BIO *bio_err = NULL;
2N/A
2N/A bio_err = BIO_new(BIO_s_file());
2N/A BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
2N/A
2N/A if (msg)
2N/A BIO_puts(bio_err, (const char *)msg);
2N/A if (dh)
2N/A DHparams_print(bio_err, dh);
2N/A
2N/A BN_print(bio_err, dh->q);
2N/A BIO_puts(bio_err, (const char *)"\n");
2N/A BIO_free(bio_err);
2N/A
2N/A}
2N/A
2N/Astatic void
2N/Aprint_pubkey(BIGNUM * key, char *msg)
2N/A{
2N/A BIO *bio_err = NULL;
2N/A
2N/A bio_err = BIO_new(BIO_s_file());
2N/A BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
2N/A
2N/A if (msg)
2N/A BIO_puts(bio_err, (const char *)msg);
2N/A if (key)
2N/A BN_print(bio_err, key);
2N/A BIO_puts(bio_err, "\n");
2N/A
2N/A BIO_free(bio_err);
2N/A
2N/A}
2N/A#endif
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * Error message generation has changed so gettext() can be used
2N/A */
2N/A#if 0
2N/Astatic char *
2N/Apkinit_pkcs11_code_to_text(int err)
2N/A{
2N/A int i;
2N/A static char uc[64];
2N/A
2N/A for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
2N/A if (pkcs11_errstrings[i].code == err)
2N/A break;
2N/A if (pkcs11_errstrings[i].text != NULL)
2N/A return (pkcs11_errstrings[i].text);
2N/A snprintf(uc, 64, gettext("unknown code 0x%x"), err);
2N/A return (uc);
2N/A}
2N/A#endif
2N/A
2N/Astatic char *
2N/Apkinit_pkcs11_code_to_text(int err) {
2N/A return pkcs11_error_table(err);
2N/A}