+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_apple_utils.h - PKINIT utilities, Mac OS X version
- *
- * Created 19 May 2004 by Doug Mitchell.
- */
-
-#ifndef _PKINIT_APPLE_UTILS_H_
-#define _PKINIT_APPLE_UTILS_H_
-
-#include <krb5/krb5.h>
-#include <Security/SecAsn1Coder.h>
-#include <Security/cssmapple.h>
-#include <CoreFoundation/CoreFoundation.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef PKI_DEBUG
-#define PKI_DEBUG 0
-#endif
-
-#if PKI_DEBUG
-
-#include <stdio.h>
-
-#define pkiDebug(args...) printf(args)
-#define pkiCssmErr(str, rtn) cssmPerror(str, rtn)
-#else
-#define pkiDebug(args...)
-#define pkiCssmErr(str, rtn)
-#endif /* PKI_DEBUG */
-
-/*
- * Macros used to initialize a declared CSSM_DATA and krb5_data to zero/NULL values.
- */
-#define INIT_CDATA(cd) cd = {0, NULL}
-#define INIT_KDATA(kd) kd = {0, 0, NULL}
-
-/* attach/detach to/from CL */
-CSSM_RETURN pkiClDetachUnload(CSSM_CL_HANDLE clHand);
-CSSM_CL_HANDLE pkiClStartup(void);
-
-/*
- * CSSM_DATA <--> krb5_ui_4
- */
-krb5_error_code pkiDataToInt(
- const CSSM_DATA *cdata,
- krb5_int32 *i); /* RETURNED */
-
-krb5_error_code pkiIntToData(
- krb5_int32 num,
- CSSM_DATA *cdata, /* allocated in coder space and RETURNED */
- SecAsn1CoderRef coder);
-
-/*
- * raw data --> krb5_data
- */
-krb5_error_code pkiDataToKrb5Data(
- const void *data,
- unsigned dataLen,
- krb5_data *kd); /* content mallocd and RETURNED */
-
-/*
- * CSSM_DATA <--> krb5_data
- *
- * CSSM_DATA data is managed by a SecAsn1CoderRef; krb5_data.data is mallocd.
- */
-krb5_error_code pkiCssmDataToKrb5Data(
- const CSSM_DATA *cd,
- krb5_data *kd); /* content mallocd and RETURNED */
-
-
-krb5_error_code pkiKrb5DataToCssm(
- const krb5_data *kd,
- CSSM_DATA *cdata, /* allocated in coder space and RETURNED */
- SecAsn1CoderRef coder);
-
-/*
- * CFDataRef --> krb5_data, mallocing the destination contents.
- */
-krb5_error_code pkiCfDataToKrb5Data(
- CFDataRef cfData,
- krb5_data *kd); /* content mallocd and RETURNED */
-
-/*
- * Non-mallocing conversion between CSSM_DATA and krb5_data
- */
-#define PKI_CSSM_TO_KRB_DATA(cd, kd) \
- do { \
- (kd)->data = (char *)(cd)->Data; \
- (kd)->length = (cd)->Length; \
- } while (0)
-
-#define PKI_KRB_TO_CSSM_DATA(kd, cd) \
- do { \
- (cd)->Data = (uint8 *)(kd)->data; \
- (cd)->Length = (kd)->length; \
- } while (0)
-
-/*
- * Compare to CSSM_DATAs. Return TRUE if they're the same else FALSE.
- */
-krb5_boolean pkiCompareCssmData(
- const CSSM_DATA *d1,
- const CSSM_DATA *d2);
-
-/*
- * krb5_timestamp <--> a mallocd string in generalized format
- */
-krb5_error_code pkiKrbTimestampToStr(
- krb5_timestamp kts,
- char **str); /* mallocd and RETURNED */
-
-krb5_error_code pkiTimeStrToKrbTimestamp(
- const char *str,
- unsigned len,
- krb5_timestamp *kts); /* RETURNED */
-
-/*
- * How many items in a NULL-terminated array of pointers?
- */
-unsigned pkiNssArraySize(
- const void **array);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKINIT_APPLE_UTILS_H_ */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_asn1.h - ASN.1 encode/decode routines for PKINIT
- *
- * Created 18 May 2004 by Doug Mitchell.
- */
-
-#ifndef _PKINIT_ASN1_H_
-#define _PKINIT_ASN1_H_
-
-#include <krb5/krb5.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* RFC 3280 AlgorithmIdentifier */
-typedef struct {
- krb5_data algorithm; /* OID */
- krb5_data parameters; /* ASN_ANY, defined by algorithm */
-} krb5int_algorithm_id;
-
-/*
- * Encode and decode AuthPack, public key version (no Diffie-Hellman components).
- */
-krb5_error_code krb5int_pkinit_auth_pack_encode(
- krb5_timestamp kctime,
- krb5_int32 cusec, /* microseconds */
- krb5_ui_4 nonce,
- const krb5_checksum *pa_checksum,
- const krb5int_algorithm_id *cms_types, /* optional */
- krb5_ui_4 num_cms_types,
- krb5_data *auth_pack); /* mallocd and RETURNED */
-
-/* all returned values are optional - pass NULL if you don't want them */
-krb5_error_code krb5int_pkinit_auth_pack_decode(
- const krb5_data *auth_pack, /* DER encoded */
- krb5_timestamp *kctime, /* RETURNED */
- krb5_ui_4 *cusec, /* microseconds, RETURNED */
- krb5_ui_4 *nonce, /* RETURNED */
- krb5_checksum *pa_checksum, /* contents mallocd and RETURNED */
- krb5int_algorithm_id **cms_types, /* mallocd and RETURNED */
- krb5_ui_4 *num_cms_types); /* RETURNED */
-
-
-/*
- * Given DER-encoded issuer and serial number, create an encoded
- * IssuerAndSerialNumber.
- */
-krb5_error_code krb5int_pkinit_issuer_serial_encode(
- const krb5_data *issuer, /* DER encoded */
- const krb5_data *serial_num,
- krb5_data *issuer_and_serial); /* content mallocd and RETURNED */
-
-/*
- * Decode IssuerAndSerialNumber.
- */
-krb5_error_code krb5int_pkinit_issuer_serial_decode(
- const krb5_data *issuer_and_serial, /* DER encoded */
- krb5_data *issuer, /* DER encoded, RETURNED */
- krb5_data *serial_num); /* RETURNED */
-
-/*
- * Top-level encode for PA-PK-AS-REQ.
- * The signed_auth_pack field is wrapped in an OCTET STRING, content
- * specific tag 0, during encode.
- */
-krb5_error_code krb5int_pkinit_pa_pk_as_req_encode(
- const krb5_data *signed_auth_pack, /* DER encoded ContentInfo */
- const krb5_data *trusted_CAs, /* optional: trustedCertifiers. Contents are
- * DER-encoded issuer/serialNumbers. */
- krb5_ui_4 num_trusted_CAs,
- const krb5_data *kdc_cert, /* optional kdcPkId, DER encoded issuer/serial */
- krb5_data *pa_pk_as_req); /* mallocd and RETURNED */
-
-/*
- * Top-level decode for PA-PK-AS-REQ. Does not perform cert verification on the
- * ContentInfo; that is returned in BER-encoded form and processed elsewhere.
- * The OCTET STRING wrapping the signed_auth_pack field is removed during the
- * decode.
- */
-krb5_error_code krb5int_pkinit_pa_pk_as_req_decode(
- const krb5_data *pa_pk_as_req,
- krb5_data *signed_auth_pack, /* DER encoded ContentInfo, RETURNED */
- /*
- * Remainder are optionally RETURNED (specify NULL for pointers to
- * items you're not interested in).
- */
- krb5_ui_4 *num_trusted_CAs, /* sizeof trusted_CAs */
- krb5_data **trusted_CAs, /* mallocd array of DER-encoded TrustedCAs
- * issuer/serial */
- krb5_data *kdc_cert); /* DER encoded issuer/serial */
-
-/*
- * Encode a ReplyKeyPack. The result is used as the Content of a SignedData.
- */
-krb5_error_code krb5int_pkinit_reply_key_pack_encode(
- const krb5_keyblock *key_block,
- const krb5_checksum *checksum,
- krb5_data *reply_key_pack); /* mallocd and RETURNED */
-
-/*
- * Decode a ReplyKeyPack.
- */
-krb5_error_code krb5int_pkinit_reply_key_pack_decode(
- const krb5_data *reply_key_pack,
- krb5_keyblock *key_block, /* RETURNED */
- krb5_checksum *checksum); /* contents mallocd and RETURNED */
-
-/*
- * Encode a PA-PK-AS-REP.
- * Exactly one of {dh_signed_data, enc_key_pack} is non-NULL on entry;
- * each is a previously encoded item.
- *
- * dh_signed_data, if specified, is an encoded DHRepInfo.
- * enc_key_pack, if specified, is EnvelopedData(signedData(ReplyKeyPack)
- */
-krb5_error_code krb5int_pkinit_pa_pk_as_rep_encode(
- const krb5_data *dh_signed_data,
- const krb5_data *enc_key_pack, /* EnvelopedData(signedData(ReplyKeyPack) */
- krb5_data *pa_pk_as_rep); /* mallocd and RETURNED */
-
-/*
- * Decode a PA-PK-AS-REP.
- * On successful return, exactly one of {dh_signed_data, enc_key_pack}
- * will be non-NULL, each of which is mallocd and must be freed by
- * caller.
- *
- * dh_signed_data, if returned, is an encoded DHRepInfo.
- * enc_key_pack, if specified, is EnvelopedData(signedData(ReplyKeyPack)
- */
-krb5_error_code krb5int_pkinit_pa_pk_as_rep_decode(
- const krb5_data *pa_pk_as_rep,
- krb5_data *dh_signed_data,
- krb5_data *enc_key_pack);
-
-/*
- * Given a DER encoded certificate, obtain the associated IssuerAndSerialNumber.
- */
-krb5_error_code krb5int_pkinit_get_issuer_serial(
- const krb5_data *cert,
- krb5_data *issuer_and_serial);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKINIT_ASN1_H_ */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_cert_store.h - PKINIT certificate storage/retrieval utilities
- *
- * Created 26 May 2004 by Doug Mitchell at Apple.
- */
-
-#ifndef _PKINIT_CERT_STORE_H_
-#define _PKINIT_CERT_STORE_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <krb5/krb5.h>
-
-/*
- * Opaque reference to a machine-dependent representation of a certificate
- * which is capable of signing. On Mac OS X this is actually a SecIdentityRef.
- */
-typedef void *krb5_pkinit_signing_cert_t;
-
-/*
- * Opaque reference to a machine-dependent representation of a certificate.
- * On Mac OS X this is actually a SecCertificateRef.
- */
-typedef void *krb5_pkinit_cert_t;
-
-/*
- * Opaque reference to a database in which PKINIT-related certificates are stored.
- */
-typedef void *krb5_pkinit_cert_db_t;
-
-/*
- * Obtain signing cert for specified principal. On successful return,
- * caller must eventually release the cert with krb5_pkinit_release_cert().
- *
- * Returns KRB5_PRINC_NOMATCH if client cert not found.
- */
-krb5_error_code krb5_pkinit_get_client_cert(
- const char *principal, /* full principal string */
- krb5_pkinit_signing_cert_t *client_cert); /* RETURNED */
-
-/*
- * Determine if the specified client has a signing cert. Returns TRUE
- * if so, else returns FALSE.
- */
-krb5_boolean krb5_pkinit_have_client_cert(
- const char *principal); /* full principal string */
-
-/*
- * Store the specified certificate (or, more likely, some platform-dependent
- * reference to it) as the specified principal's signing cert. Passing
- * in NULL for the client_cert has the effect of deleting the relevant entry
- * in the cert storage.
- */
-krb5_error_code krb5_pkinit_set_client_cert_from_signing_cert(
- const char *principal, /* full principal string */
- krb5_pkinit_signing_cert_t client_cert);
-krb5_error_code krb5_pkinit_set_client_cert(
- const char *principal, /* full principal string */
- krb5_pkinit_cert_t client_cert);
-
-/*
- * Obtain a reference to the client's cert database. Specify either principal
- * name or client_cert as obtained from krb5_pkinit_get_client_cert().
- */
-krb5_error_code krb5_pkinit_get_client_cert_db(
- const char *principal, /* optional, full principal string */
- krb5_pkinit_signing_cert_t client_cert, /* optional, from krb5_pkinit_get_client_cert() */
- krb5_pkinit_cert_db_t *client_cert_db); /* RETURNED */
-
-/*
- * Obtain the KDC signing cert, with optional CA and specific cert specifiers.
- * CAs and cert specifiers are in the form of DER-encoded issuerAndSerialNumbers.
- *
- * The client_spec argument is typically provided by the client as kdcPkId.
- *
- * If trusted_CAs and client_spec are NULL, a platform-dependent preferred
- * KDC signing cert is returned, if one exists.
- *
- * On successful return, caller must eventually release the cert with
- * krb5_pkinit_release_cert(). Outside of an unusual test configuration this =
- *
- * Returns KRB5_PRINC_NOMATCH if KDC cert not found.
- *
- */
-krb5_error_code krb5_pkinit_get_kdc_cert(
- krb5_ui_4 num_trusted_CAs, /* sizeof *trusted_CAs */
- krb5_data *trusted_CAs, /* optional */
- krb5_data *client_spec, /* optional */
- krb5_pkinit_signing_cert_t *kdc_cert); /* RETURNED */
-
-/*
- * Obtain a reference to the KDC's cert database.
- */
-krb5_error_code krb5_pkinit_get_kdc_cert_db(
- krb5_pkinit_cert_db_t *kdc_cert_db); /* RETURNED */
-
-/*
- * Release certificate references obtained via krb5_pkinit_get_client_cert() and
- * krb5_pkinit_get_kdc_cert().
- */
-extern void krb5_pkinit_release_cert(
- krb5_pkinit_signing_cert_t cert);
-
-/*
- * Release database references obtained via krb5_pkinit_get_client_cert_db() and
- * krb5_pkinit_get_kdc_cert_db().
- */
-extern void krb5_pkinit_release_cert_db(
- krb5_pkinit_cert_db_t cert_db);
-
-/*
- * Obtain a mallocd C-string representation of a certificate's SHA1 digest.
- * Only error is a NULL return indicating memory failure.
- * Caller must free the returned string.
- */
-char *krb5_pkinit_cert_hash_str(
- const krb5_data *cert);
-
-/*
- * Obtain a client's optional list of trusted KDC CA certs (trustedCertifiers)
- * and/or trusted KDC cert (kdcPkId) for a given client and server.
- * All returned values are mallocd and must be freed by caller; the contents
- * of the krb5_datas are DER-encoded certificates.
- */
-krb5_error_code krb5_pkinit_get_server_certs(
- const char *client_principal,
- const char *server_principal,
- krb5_data **trusted_CAs, /* RETURNED, though return value may be NULL */
- krb5_ui_4 *num_trusted_CAs, /* RETURNED */
- krb5_data *kdc_cert); /* RETURNED, though may be 0/NULL */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKINIT_CERT_STORE_H_ */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_client.h - Client side routines for PKINIT
- *
- * Created 20 May 2004 by Doug Mitchell at Apple.
- */
-
-#ifndef _PKINIT_CLIENT_H_
-#define _PKINIT_CLIENT_H_
-
-#include <krb5/krb5.h>
-#include "pkinit_cms.h"
-#include "pkinit_cert_store.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Create a PA-PK-AS-REQ message.
- */
-krb5_error_code krb5int_pkinit_as_req_create(
- krb5_context context,
- krb5_timestamp kctime,
- krb5_int32 cusec, /* microseconds */
- krb5_ui_4 nonce,
- const krb5_checksum *cksum,
- krb5_pkinit_signing_cert_t client_cert, /* required! */
-
- /*
- * trusted_CAs correponds to PA-PK-AS-REQ.trustedCertifiers.
- * Expressed here as an optional list of DER-encoded certs.
- */
- const krb5_data *trusted_CAs,
- krb5_ui_4 num_trusted_CAs,
-
- /* optional PA-PK-AS-REQ.kdcPkId, expressed here as a
- * DER-encoded cert */
- const krb5_data *kdc_cert,
- krb5_data *as_req); /* mallocd and RETURNED */
-
-/*
- * Parse PA-PK-AS-REP message. Optionally evaluates the message's certificate chain.
- * Optionally returns various components.
- */
-krb5_error_code krb5int_pkinit_as_rep_parse(
- krb5_context context,
- const krb5_data *as_rep,
- krb5_pkinit_signing_cert_t client_cert, /* required for decryption */
- krb5_keyblock *key_block, /* RETURNED */
- krb5_checksum *checksum, /* checksum of corresponding AS-REQ */
- /* contents mallocd and RETURNED */
- krb5int_cert_sig_status *cert_status, /* RETURNED */
-
- /*
- * Cert fields, all optionally RETURNED.
- *
- * signer_cert is the DER-encoded leaf cert from the incoming SignedData.
- * all_certs is an array of all of the certs in the incoming SignedData,
- * in full DER-encoded form.
- */
- krb5_data *signer_cert, /* content mallocd */
- unsigned *num_all_certs, /* sizeof *all_certs */
- krb5_data **all_certs); /* krb5_data's and their content mallocd */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKINIT_CLIENT_H_ */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_apple_cms.h - CMS encode/decode routines, Mac OS X version
- *
- * Created 19 May 2004 by Doug Mitchell at Apple.
- */
-
-#ifndef _PKINIT_CMS_H_
-#define _PKINIT_CMS_H_
-
-#include <krb5/krb5.h>
-#include "pkinit_cert_store.h" /* for krb5_pkinit_signing_cert_t */
-#include "pkinit_asn1.h" /* for krb5int_algorithm_id */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Define ContentType for a SignedData and EnvelopedData.
- */
-enum {
- /* normal CMS ContentTypes */
- ECT_Data,
- ECT_SignedData,
- ECT_EnvelopedData,
- ECT_EncryptedData,
-
- /*
- * For SignedAuthPack
- * pkauthdata: { iso (1) org (3) dod (6) internet (1)
- * security (5) kerberosv5 (2) pkinit (3) pkauthdata (1)}
- */
- ECT_PkAuthData,
-
- /*
- * For ReplyKeyPack
- * pkrkeydata: { iso (1) org (3) dod (6) internet (1)
- * security (5) kerberosv5 (2) pkinit (3) pkrkeydata (3) }
- */
- ECT_PkReplyKeyKata,
-
- /*
- * Other - i.e., unrecognized ContentType on decode.
- */
- ECT_Other
-};
-typedef krb5_int32 krb5int_cms_content_type;
-
-/*
- * Result of certificate and signature verification.
- */
-enum {
- pki_cs_good = 0,
- pki_not_signed, /* message not signed */
- pki_not_evaluated, /* signed, but not evaluated per caller request */
- /* remainder imply good signature on the message proper, i.e., these
- * are all certificate errors. */
- pki_cs_sig_verify_fail, /* signature verification failed */
- pki_cs_bad_leaf, /* leaf/subject cert itself is plain bad */
- pki_cs_no_root, /* looks good but not verifiable to any root */
- pki_cs_unknown_root, /* verified to root we don't recognize */
- pki_cs_expired, /* expired */
- pki_cs_not_valid_yet, /* cert not valid yet */
- pki_cs_revoked, /* revoked via CRL or OCSP */
- pki_cs_untrusted, /* marked by user as untrusted */
- pki_bad_cms, /* CMS Format precluded verification */
- pki_bad_key_use, /* Bad ExtendedKeyUse or KeyUsage extension */
- pki_bad_digest, /* unacceptable CMS digest algorithm */
- pki_cs_other_err /* other cert verify error */
-};
-typedef krb5_int32 krb5int_cert_sig_status;
-
-/*
- * Create a CMS message: either encrypted (EnvelopedData), signed
- * (SignedData), or both (EnvelopedData(SignedData(content)).
- *
- * The message is signed iff signing_cert is non-NULL.
- * The message is encrypted iff recip_cert is non-NULL.
- *
- * The content_type argument specifies to the eContentType
- * for a SignedData's EncapsulatedContentInfo; it's ignored
- * if the message is not to be signed.
- *
- * The cms_types argument optionally specifies a list, in order
- * of decreasing preference, of CMS algorithms to use in the
- * creation of the CMS message.
- */
-krb5_error_code krb5int_pkinit_create_cms_msg(
- const krb5_data *content, /* Content */
- krb5_pkinit_signing_cert_t signing_cert, /* optional: signed by this cert */
- const krb5_data *recip_cert, /* optional: encrypted with this cert */
- krb5int_cms_content_type content_type, /* OID for EncapsulatedData */
- krb5_ui_4 num_cms_types, /* optional */
- const krb5int_algorithm_id *cms_types, /* optional */
- krb5_data *content_info); /* contents mallocd and RETURNED */
-
-/*
- * Parse a ContentInfo as best we can. All returned fields are optional -
- * pass NULL for values you don't need.
- *
- * If signer_cert_status is NULL on entry, NO signature or cert evaluation
- * will be performed.
- *
- * The is_client_msg argument indicates whether the CMS message originated
- * from the client (TRUE) or server (FALSE) and may be used in platform-
- * dependent certificate evaluation.
- *
- * Note that signature and certificate verification errors do NOT cause
- * this routine itself to return an error; caller is reponsible for
- * handling such errors per the signer_cert_status out parameter.
- */
-krb5_error_code krb5int_pkinit_parse_cms_msg(
- const krb5_data *content_info,
- krb5_pkinit_cert_db_t cert_db, /* may be required for SignedData */
- krb5_boolean is_client_msg, /* TRUE : msg is from client */
- krb5_boolean *is_signed, /* RETURNED */
- krb5_boolean *is_encrypted, /* RETURNED */
- krb5_data *raw_data, /* RETURNED */
- krb5int_cms_content_type *inner_content_type,/* Returned, ContentType of
- * EncapsulatedData if
- * *is_signed true */
- /* returned for type SignedData only */
- krb5_data *signer_cert, /* RETURNED */
- krb5int_cert_sig_status *signer_cert_status,/* RETURNED */
- unsigned *num_all_certs, /* size of *all_certs RETURNED */
- krb5_data **all_certs); /* entire cert chain RETURNED */
-
-/*
- * An AuthPack contains an optional set of AlgorithmIdentifiers
- * which define the CMS algorithms supported by the client, in
- * order of decreasing preference.
- *
- * krb5int_pkinit_get_cms_types() is a CMS-implementation-dependent
- * function returning supported CMS algorithms in the form of a
- * pointer and a length suitable for passing to
- * krb5int_pkinit_auth_pack_encode. If no preference is to be expressed,
- * this function returns NULL/0 (without returning a nonzero krb5_error_code).
- *
- * krb5int_pkinit_free_cms_types() frees the pointer obtained
- * from krb5int_pkinit_get_cms_types() as necessary.
- */
-krb5_error_code krb5int_pkinit_get_cms_types(
- krb5int_algorithm_id **supported_cms_types, /* RETURNED */
- krb5_ui_4 *num_supported_cms_types); /* RETURNED */
-
-krb5_error_code krb5int_pkinit_free_cms_types(
- krb5int_algorithm_id *supported_cms_types,
- krb5_ui_4 num_supported_cms_types);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKINIT_CMS_H_ */
kadmin_parse_princ_args(int argc, char *argv[], kadm5_principal_ent_t oprinc,
long *mask, char **pass, krb5_boolean *randkey,
krb5_key_salt_tuple **ks_tuple, int *n_ks_tuple,
-#if APPLE_PKINIT
- char **cert_hash,
-#endif /* APPLE_PKINIT */
char *caller)
{
int i, attrib_set;
*pass = NULL;
*n_ks_tuple = 0;
*ks_tuple = NULL;
-#if APPLE_PKINIT
- *cert_hash = NULL;
-#endif /* APPLE_PKINIT */
time(&now);
*randkey = FALSE;
for (i = 1; i < argc - 1; i++) {
*randkey = TRUE;
continue;
}
-#if APPLE_PKINIT
- if (strlen(argv[i]) == 9 && !strcmp("-certhash", argv[i])) {
- if (++i > argc - 2)
- return -1;
- else {
- *cert_hash = argv[i];
- continue;
- }
- }
-#endif /* APPLE_PKINIT */
if (strlen(argv[i]) == 7 && !strcmp("-unlock", argv[i])) {
unlock_princ(oprinc, mask, caller);
continue;
krb5_error_code retval;
char newpw[1024], dummybuf[256];
static char prompt1[1024], prompt2[1024];
-#if APPLE_PKINIT
- char *cert_hash = NULL;
-#endif /* APPLE_PKINIT */
/* Zero all fields in request structure */
memset(&princ, 0, sizeof(princ));
princ.attributes = 0;
if (kadmin_parse_princ_args(argc, argv, &princ, &mask, &pass, &randkey,
- &ks_tuple, &n_ks_tuple,
-#if APPLE_PKINIT
- &cert_hash,
-#endif /* APPLE_PKINIT */
- "add_principal")) {
+ &ks_tuple, &n_ks_tuple, "add_principal")) {
kadmin_addprinc_usage();
goto cleanup;
}
-#if APPLE_PKINIT
- if(cert_hash != NULL) {
- fprintf(stderr,
- "add_principal: -certhash not allowed; use modify_principal\n");
- goto cleanup;
- }
-#endif /* APPLE_PKINIT */
-
retval = krb5_unparse_name(context, princ.principal, &canon);
if (retval) {
com_err("add_principal", retval, _("while canonicalizing principal"));
krb5_boolean randkey = FALSE;
int n_ks_tuple = 0;
krb5_key_salt_tuple *ks_tuple = NULL;
-#if APPLE_PKINIT
- char *cert_hash = NULL;
-#endif /* APPLE_PKINIT */
if (argc < 2) {
kadmin_modprinc_usage();
&princ, &mask,
&pass, &randkey,
&ks_tuple, &n_ks_tuple,
-#if APPLE_PKINIT
- &cert_hash,
-#endif /* APPLE_PKINIT */
"modify_principal");
if (retval || ks_tuple != NULL || randkey || pass) {
kadmin_modprinc_usage();
goto cleanup;
}
-#if APPLE_PKINIT
- if (cert_hash) {
- /*
- * Use something other than the 1st preferred enctype here for fallback
- * to pwd authentication
- */
- krb5_key_salt_tuple key_salt = {ENCTYPE_ARCFOUR_HMAC, KRB5_KDB_SALTTYPE_CERTHASH};
- krb5_keyblock keyblock;
- kadm5_ret_t kadmin_rtn;
-
- keyblock.magic = KV5M_KEYBLOCK;
- keyblock.enctype = ENCTYPE_ARCFOUR_HMAC;
- keyblock.length = strlen(cert_hash);
- keyblock.contents = (krb5_octet *)cert_hash;
- kadmin_rtn = kadm5_setkey_principal_3(handle, kprinc,
- TRUE, /* keepold - we're appending */
- 1, &key_salt,
- &keyblock, 1);
- if (kadmin_rtn) {
- com_err("modify_principal", kadmin_rtn,
- "while adding certhash for \"%s\".", canon);
- printf("realm %s data %s\n", (char *)kprinc->realm.data, (char *)kprinc->data->data);
- goto cleanup;
- }
- retval = 0;
- }
-#endif /* APPLE_PKINIT */
if (mask) {
/* Skip this if all we're doing is setting certhash. */
retval = kadm5_modify_principal(handle, &princ, mask);
#include "adm_proto.h"
#include "extern.h"
-#if APPLE_PKINIT
-#define AS_REQ_DEBUG 0
-#if AS_REQ_DEBUG
-#define asReqDebug(args...) printf(args)
-#else
-#define asReqDebug(args...)
-#endif
-#endif /* APPLE_PKINIT */
-
static krb5_error_code
prepare_error_as(struct kdc_request_state *, krb5_kdc_req *,
int, krb5_pa_data **, krb5_boolean, krb5_principal,
goto egress;
}
-#if APPLE_PKINIT
- asReqDebug("process_as_req reply realm %s name %s\n",
- reply.client->realm.data, reply.client->data->data);
-#endif /* APPLE_PKINIT */
-
-
-
errcode = handle_authdata(kdc_context,
state->c_flags,
state->client,
state->req_pkt = req_pkt;
state->from = from;
-#if APPLE_PKINIT
- asReqDebug("process_as_req top realm %s name %s\n",
- request->client->realm.data, request->client->data->data);
-#endif /* APPLE_PKINIT */
-
if (state->request->msg_type != KRB5_AS_REQ) {
state->status = "msg_type mismatch";
errcode = KRB5_BADMSGTYPE;
#include "extern.h"
#include <stdio.h>
#include "adm_proto.h"
-#if APPLE_PKINIT
-#include "pkinit_server.h"
-#include "pkinit_cert_store.h"
-#endif /* APPLE_PKINIT */
#include <syslog.h>
krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq);
-#if APPLE_PKINIT
-/* PKINIT preauth support */
-static krb5_error_code get_pkinit_edata(
- krb5_context context,
- krb5_kdc_req *request,
- krb5_db_entry *client,
- krb5_db_entry *server,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- krb5_pa_data *pa_data);
-static krb5_error_code verify_pkinit_request(
- krb5_context context,
- krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request,
- krb5_enc_tkt_part *enc_tkt_reply,
- krb5_pa_data *data,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- void **pa_request_context,
- krb5_data **e_data,
- krb5_authdata ***authz_data);
-static krb5_error_code return_pkinit_response(
- krb5_context context,
- krb5_pa_data * padata,
- krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request,
- krb5_kdc_rep *reply,
- krb5_key_data *client_key,
- krb5_keyblock *encrypting_key,
- krb5_pa_data **send_pa,
- preauth_get_entry_data_proc get_entry_data,
- void *pa_module_context,
- void **pa_request_context);
-#endif /* APPLE_PKINIT */
static preauth_system static_preauth_systems[] = {
-#if APPLE_PKINIT
- {
- "pkinit",
- KRB5_PADATA_PK_AS_REQ,
- PA_SUFFICIENT,
- NULL, /* pa_sys_context */
- NULL, /* init */
- NULL, /* fini */
- get_pkinit_edata,
- verify_pkinit_request,
- return_pkinit_response,
- NULL /* free_modreq */
- },
-#endif /* APPLE_PKINIT */
{
"FAST",
KRB5_PADATA_FX_FAST,
return retval;
}
-
-
-#if APPLE_PKINIT
-/* PKINIT preauth support */
-#define PKINIT_DEBUG 0
-#if PKINIT_DEBUG
-#define kdcPkinitDebug(args...) printf(args)
-#else
-#define kdcPkinitDebug(args...)
-#endif
-
-/*
- * get_edata() - our only job is to determine whether this KDC is capable of
- * performing PKINIT. We infer that from the presence or absence of any
- * KDC signing cert.
- */
-static krb5_error_code get_pkinit_edata(
- krb5_context context,
- krb5_kdc_req *request,
- krb5_db_entry *client,
- krb5_db_entry *server,
- preauth_get_entry_data_proc pkinit_get_entry_data,
- void *pa_module_context,
- krb5_pa_data *pa_data)
-{
- krb5_pkinit_signing_cert_t cert = NULL;
- krb5_error_code err = krb5_pkinit_get_kdc_cert(0, NULL, NULL, &cert);
-
- kdcPkinitDebug("get_pkinit_edata: kdc cert %s\n", err ? "NOT FOUND" : "FOUND");
- if(cert) {
- krb5_pkinit_release_cert(cert);
- }
- return err;
-}
-
-/*
- * This is 0 only for testing until the KDC DB contains
- * the hash of the client cert
- */
-#define REQUIRE_CLIENT_CERT_MATCH 1
-
-static krb5_error_code verify_pkinit_request(
- krb5_context context,
- krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request,
- krb5_enc_tkt_part *enc_tkt_reply,
- krb5_pa_data *data,
- preauth_get_entry_data_proc pkinit_get_entry_data,
- void *pa_module_context,
- void **pa_request_context,
- krb5_data **e_data,
- krb5_authdata ***authz_data)
-{
- krb5_error_code krtn;
- krb5_data pa_data;
- krb5_data *der_req = NULL;
- krb5_boolean valid_cksum;
- char *cert_hash = NULL;
- unsigned cert_hash_len;
- unsigned key_dex;
- unsigned cert_match = 0;
- krb5_keyblock decrypted_key, *mkey_ptr;
-
- /* the data we get from the AS-REQ */
- krb5_timestamp client_ctime = 0;
- krb5_ui_4 client_cusec = 0;
- krb5_timestamp kdc_ctime = 0;
- krb5_int32 kdc_cusec = 0;
- krb5_ui_4 nonce = 0;
- krb5_checksum pa_cksum;
- krb5int_cert_sig_status cert_sig_status;
- krb5_data client_cert = {0, 0, NULL};
-
- krb5_kdc_req *tmp_as_req = NULL;
-
- kdcPkinitDebug("verify_pkinit_request\n");
-
- decrypted_key.contents = NULL;
- pa_data.data = (char *)data->contents;
- pa_data.length = data->length;
- krtn = krb5int_pkinit_as_req_parse(context, &pa_data,
- &client_ctime, &client_cusec,
- &nonce, &pa_cksum,
- &cert_sig_status,
- NULL, NULL,/* num_cms_types, cms_types */
- &client_cert, /* signer_cert */
- /* remaining fields unused (for now) */
- NULL, NULL,/* num_all_certs, all_certs */
- NULL, NULL,/* num_trusted_CAs, trusted_CAs */
- NULL); /* kdc_cert */
- if(krtn) {
- kdcPkinitDebug("pa_pk_as_req_parse returned %d; PKINIT aborting.\n",
- (int)krtn);
- return krtn;
- }
-#if PKINIT_DEBUG
- if(cert_sig_status != pki_cs_good) {
- kdcPkinitDebug("verify_pkinit_request: cert_sig_status %d\n",
- (int)cert_sig_status);
- }
-#endif /* PKINIT_DEBUG */
-
- /*
- * Verify signature and cert.
- * FIXME: The spec calls for an e-data with error-specific type to be
- * returned on error here. TD_TRUSTED_CERTIFIERS
- * to be returned to the client here. There is no way for a preauth
- * module to pass back e-data to process_as_req at this time. We
- * might want to add such capability via an out param to check_padata
- * and to its callees.
- */
- switch(cert_sig_status) {
- case pki_cs_good:
- break;
- case pki_cs_sig_verify_fail:
- /* no e-data */
- krtn = KDC_ERR_INVALID_SIG;
- goto cleanup;
- case pki_cs_no_root:
- case pki_cs_unknown_root:
- case pki_cs_untrusted:
- /*
- * Can't verify to known root.
- * e-data TD_TRUSTED_CERTIFIERS
- */
- kdcPkinitDebug("verify_pkinit_request: KDC_ERR_CANT_VERIFY_CERTIFICATE\n");
- krtn = KDC_ERR_CANT_VERIFY_CERTIFICATE;
- goto cleanup;
- case pki_cs_bad_leaf:
- case pki_cs_expired:
- case pki_cs_not_valid_yet:
- /*
- * Problems with client cert itself.
- * e-data type TD_INVALID_CERTIFICATES
- */
- krtn = KDC_ERR_INVALID_CERTIFICATE;
- goto cleanup;
- case pki_cs_revoked:
- /* e-data type TD-INVALID-CERTIFICATES */
- krtn = KDC_ERR_REVOKED_CERTIFICATE;
- goto cleanup;
- case pki_bad_key_use:
- krtn = KDC_ERR_INCONSISTENT_KEY_PURPOSE;
- /* no e-data */
- goto cleanup;
- case pki_bad_digest:
- /* undefined (explicitly!) e-data */
- krtn = KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
- goto cleanup;
- case pki_bad_cms:
- case pki_cs_other_err:
- default:
- krtn = KRB5KDC_ERR_PREAUTH_FAILED;
- goto cleanup;
- }
-
- krtn = krb5_us_timeofday(context, &kdc_ctime, &kdc_cusec);
- if(krtn) {
- goto cleanup;
- }
- if (labs(kdc_ctime - client_ctime) > context->clockskew) {
- kdcPkinitDebug("verify_pkinit_request: clock skew violation client %d svr %d\n",
- (int)client_ctime, (int)kdc_ctime);
- krtn = KRB5KRB_AP_ERR_SKEW;
- goto cleanup;
- }
-
- /*
- * The KDC may have modified the request after decoding it.
- * We need to compute the checksum on the data that
- * came from the client. Therefore, we use the original
- * packet contents.
- */
- krtn = decode_krb5_as_req(req_pkt, &tmp_as_req);
- if(krtn) {
- kdcPkinitDebug("decode_krb5_as_req returned %d\n", (int)krtn);
- goto cleanup;
- }
-
- /* calculate and compare checksum */
- krtn = encode_krb5_kdc_req_body(tmp_as_req, &der_req);
- if(krtn) {
- kdcPkinitDebug("encode_krb5_kdc_req_body returned %d\n", (int)krtn);
- goto cleanup;
- }
- krtn = krb5_c_verify_checksum(context, NULL, 0, der_req,
- &pa_cksum, &valid_cksum);
- if(krtn) {
- kdcPkinitDebug("krb5_c_verify_checksum returned %d\n", (int)krtn);
- goto cleanup;
- }
- if(!valid_cksum) {
- kdcPkinitDebug("verify_pkinit_request: checksum error\n");
- krtn = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- goto cleanup;
- }
-
-#if REQUIRE_CLIENT_CERT_MATCH
- /* look up in the KDB to ensure correct client/cert binding */
- cert_hash = krb5_pkinit_cert_hash_str(&client_cert);
- if(cert_hash == NULL) {
- krtn = ENOMEM;
- goto cleanup;
- }
- cert_hash_len = strlen(cert_hash);
- for(key_dex=0; key_dex<client->n_key_data; key_dex++) {
- krb5_key_data *key_data = &client->key_data[key_dex];
- kdcPkinitDebug("--- key %u type[0] %u length[0] %u type[1] %u length[1] %u\n",
- key_dex,
- key_data->key_data_type[0], key_data->key_data_length[0],
- key_data->key_data_type[1], key_data->key_data_length[1]);
- if(key_data->key_data_type[1] != KRB5_KDB_SALTTYPE_CERTHASH) {
- continue;
- }
-
- /*
- * Unfortunately this key is stored encrypted even though it's
- * not sensitive...
- */
- krtn = krb5_dbe_decrypt_key_data(context, NULL, key_data,
- &decrypted_key, NULL);
- if(krtn) {
- kdcPkinitDebug("verify_pkinit_request: error decrypting cert hash block\n");
- break;
- }
- if((decrypted_key.contents != NULL) &&
- (cert_hash_len == decrypted_key.length) &&
- !memcmp(decrypted_key.contents, cert_hash, cert_hash_len)) {
- cert_match = 1;
- break;
- }
- }
- if(decrypted_key.contents) {
- krb5_free_keyblock_contents(context, &decrypted_key);
- }
- if(!cert_match) {
- kdcPkinitDebug("verify_pkinit_request: client cert does not match\n");
- krtn = KDC_ERR_CLIENT_NOT_TRUSTED;
- goto cleanup;
- }
-#endif /* REQUIRE_CLIENT_CERT_MATCH */
- krtn = 0;
- setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
-
-cleanup:
- if(pa_cksum.contents) {
- free(pa_cksum.contents);
- }
- if (tmp_as_req) {
- krb5_free_kdc_req(context, tmp_as_req);
- }
- if (der_req) {
- krb5_free_data(context, der_req);
- }
- if(cert_hash) {
- free(cert_hash);
- }
- if(client_cert.data) {
- free(client_cert.data);
- }
- kdcPkinitDebug("verify_pkinit_request: returning %d\n", (int)krtn);
- return krtn;
-}
-
-static krb5_error_code return_pkinit_response(
- krb5_context context,
- krb5_pa_data * padata,
- krb5_db_entry *client,
- krb5_data *req_pkt,
- krb5_kdc_req *request,
- krb5_kdc_rep *reply,
- krb5_key_data *client_key,
- krb5_keyblock *encrypting_key,
- krb5_pa_data **send_pa,
- preauth_get_entry_data_proc pkinit_get_entry_data,
- void *pa_module_context,
- void **pa_request_context)
-{
- krb5_error_code krtn;
- krb5_data pa_data;
- krb5_pkinit_signing_cert_t signing_cert = NULL;
- krb5_checksum as_req_checksum = {0};
- krb5_data *encoded_as_req = NULL;
- krb5int_algorithm_id *cms_types = NULL;
- krb5_ui_4 num_cms_types = 0;
-
- /* the data we get from the AS-REQ */
- krb5_ui_4 nonce = 0;
- krb5_data client_cert = {0};
-
- /*
- * Trusted CA list and specific KC cert optionally obtained via
- * krb5int_pkinit_as_req_parse(). All are DER-encoded
- * issuerAndSerialNumbers.
- */
- krb5_data *trusted_CAs = NULL;
- krb5_ui_4 num_trusted_CAs;
- krb5_data kdc_cert = {0};
-
- if (padata == NULL) {
- /* Client has to send us something */
- return 0;
- }
-
- kdcPkinitDebug("return_pkinit_response\n");
- pa_data.data = (char *)padata->contents;
- pa_data.length = padata->length;
-
- /*
- * We've already verified; just obtain the fields we need to create a response
- */
- krtn = krb5int_pkinit_as_req_parse(context,
- &pa_data,
- NULL, NULL, &nonce, /* ctime, cusec, nonce */
- NULL, NULL, /* pa_cksum, cert_status */
- &num_cms_types, &cms_types,
- &client_cert, /* signer_cert: we encrypt for this */
- /* remaining fields unused (for now) */
- NULL, NULL, /* num_all_certs, all_certs */
- &num_trusted_CAs, &trusted_CAs,
- &kdc_cert);
- if(krtn) {
- kdcPkinitDebug("pa_pk_as_req_parse returned %d; PKINIT aborting.\n",
- (int)krtn);
- goto cleanup;
- }
- if(client_cert.data == NULL) {
- kdcPkinitDebug("pa_pk_as_req_parse failed to give a client_cert; aborting.\n");
- krtn = KRB5KDC_ERR_PREAUTH_FAILED;
- goto cleanup;
- }
-
- if(krb5_pkinit_get_kdc_cert(num_trusted_CAs, trusted_CAs,
- (kdc_cert.data ? &kdc_cert : NULL),
- &signing_cert)) {
- /*
- * Since get_pkinit_edata was able to obtain *some* KDC cert,
- * this means that we can't satisfy the client's requirement.
- * FIXME - particular error status for this?
- */
- kdcPkinitDebug("return_pkinit_response: NO appropriate signing cert!\n");
- krtn = KRB5KDC_ERR_PREAUTH_FAILED;
- goto cleanup;
- }
-
- /*
- * Cook up keyblock for caller and for outgoing AS-REP.
- * FIXME how much is known to be valid about encrypting_key?
- * Will encrypting_key->enctype always be valid here? Seems that
- * if we allow for clients without a shared secret (i.e. preauth
- * by PKINIT only) there won't be a valid encrypting_key set up
- * here for us.
- */
- krb5_free_keyblock_contents(context, encrypting_key);
- krb5_c_make_random_key(context, encrypting_key->enctype, encrypting_key);
-
- /* calculate checksum of incoming AS-REQ */
- krtn = encode_krb5_as_req(request, &encoded_as_req);
- if(krtn) {
- kdcPkinitDebug("encode_krb5_as_req returned %d; PKINIT aborting.\n", (int)krtn);
- goto cleanup;
- }
- krtn = krb5_c_make_checksum(context, context->kdc_req_sumtype,
- encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
- encoded_as_req, &as_req_checksum);
- if(krtn) {
- goto cleanup;
- }
-
- /*
- * FIXME: here we assume that the client has one cert - the one that
- * signed the AuthPack in the request (and that we therefore obtained from
- * krb5int_pkinit_as_req_parse()), and the one we're using to encrypt the
- * ReplyKeyPack with here. This may need rethinking.
- */
- krtn = krb5int_pkinit_as_rep_create(context,
- encrypting_key, &as_req_checksum,
- signing_cert, TRUE,
- &client_cert,
- num_cms_types, cms_types,
- num_trusted_CAs, trusted_CAs,
- (kdc_cert.data ? &kdc_cert : NULL),
- &pa_data);
- if(krtn) {
- kdcPkinitDebug("pa_pk_as_rep_create returned %d; PKINIT aborting.\n",
- (int)krtn);
- goto cleanup;
- }
-
- *send_pa = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
- if(*send_pa == NULL) {
- krtn = ENOMEM;
- free(pa_data.data);
- goto cleanup;
- }
- (*send_pa)->magic = KV5M_PA_DATA;
- (*send_pa)->pa_type = KRB5_PADATA_PK_AS_REP;
- (*send_pa)->length = pa_data.length;
- (*send_pa)->contents = (krb5_octet *)pa_data.data;
- krtn = 0;
-
-#if PKINIT_DEBUG
- fprintf(stderr, "return_pkinit_response: SUCCESS\n");
- fprintf(stderr, "nonce 0x%x enctype %d keydata %02x %02x %02x %02x...\n",
- (int)nonce, (int)encrypting_key->enctype,
- encrypting_key->contents[0], encrypting_key->contents[1],
- encrypting_key->contents[2], encrypting_key->contents[3]);
-#endif
-
-cleanup:
- /* all of this was allocd by krb5int_pkinit_as_req_parse() */
- if(signing_cert) {
- krb5_pkinit_release_cert(signing_cert);
- }
- if(cms_types) {
- unsigned dex;
- krb5int_algorithm_id *alg_id;
-
- for(dex=0; dex<num_cms_types; dex++) {
- alg_id = &cms_types[dex];
- if(alg_id->algorithm.data) {
- free(alg_id->algorithm.data);
- }
- if(alg_id->parameters.data) {
- free(alg_id->parameters.data);
- }
- }
- free(cms_types);
- }
- if(trusted_CAs) {
- unsigned dex;
- for(dex=0; dex<num_trusted_CAs; dex++) {
- free(trusted_CAs[dex].data);
- }
- free(trusted_CAs);
- }
- if(kdc_cert.data) {
- free(kdc_cert.data);
- }
- if(client_cert.data) {
- free(client_cert.data);
- }
- if(encoded_as_req) {
- krb5_free_data(context, encoded_as_req);
- }
- return krtn;
-}
-
-#endif /* APPLE_PKINIT */
-
/*
* Returns TRUE if the PAC should be included
*/
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_apple_server.c - Server side routines for PKINIT, Mac OS X version
- *
- * Created 21 May 2004 by Doug Mitchell at Apple.
- */
-
-#if APPLE_PKINIT
-
-#include "pkinit_server.h"
-#include "pkinit_asn1.h"
-#include "pkinit_cms.h"
-#include <assert.h>
-
-#define PKINIT_DEBUG 0
-#if PKINIT_DEBUG
-#define pkiDebug(args...) printf(args)
-#else
-#define pkiDebug(args...)
-#endif
-
-/*
- * Parse PA-PK-AS-REQ message. Optionally evaluates the message's certificate chain.
- * Optionally returns various components.
- */
-krb5_error_code krb5int_pkinit_as_req_parse(
- krb5_context context,
- const krb5_data *as_req,
- krb5_timestamp *kctime, /* optionally RETURNED */
- krb5_ui_4 *cusec, /* microseconds, optionally RETURNED */
- krb5_ui_4 *nonce, /* optionally RETURNED */
- krb5_checksum *pa_cksum, /* optional, contents mallocd and RETURNED */
- krb5int_cert_sig_status *cert_status,/* optionally RETURNED */
- krb5_ui_4 *num_cms_types, /* optionally RETURNED */
- krb5int_algorithm_id **cms_types, /* optionally mallocd and RETURNED */
-
- /*
- * Cert fields, all optionally RETURNED.
- *
- * signer_cert is the full X.509 leaf cert from the incoming SignedData.
- * all_certs is an array of all of the certs in the incoming SignedData,
- * in full X.509 form.
- */
- krb5_data *signer_cert, /* content mallocd */
- krb5_ui_4 *num_all_certs, /* sizeof *all_certs */
- krb5_data **all_certs, /* krb5_data's and their content mallocd */
-
- /*
- * Array of trustedCertifiers, optionally RETURNED. These are DER-encoded
- * issuer/serial numbers.
- */
- krb5_ui_4 *num_trusted_CAs, /* sizeof *trusted_CAs */
- krb5_data **trusted_CAs, /* krb5_data's and their content mallocd */
-
- /* KDC cert specified by client as kdcPkId. DER-encoded issuer/serial number. */
- krb5_data *kdc_cert)
-{
- krb5_error_code krtn;
- krb5_data signed_auth_pack = {0, 0, NULL};
- krb5_data raw_auth_pack = {0, 0, NULL};
- krb5_data *raw_auth_pack_p = NULL;
- krb5_boolean proceed = FALSE;
- krb5_boolean need_auth_pack = FALSE;
- krb5int_cms_content_type content_type;
- krb5_pkinit_cert_db_t cert_db = NULL;
- krb5_boolean is_signed;
- krb5_boolean is_encrypted;
-
- assert(as_req != NULL);
-
- /*
- * We always have to decode the top-level AS-REQ...
- */
- krtn = krb5int_pkinit_pa_pk_as_req_decode(as_req, &signed_auth_pack,
- num_trusted_CAs, trusted_CAs, /* optional */
- kdc_cert); /* optional */
- if (krtn) {
- pkiDebug("krb5int_pkinit_pa_pk_as_req_decode returned %d\n", (int)krtn);
- return krtn;
- }
-
- /* Do we need info about or from the ContentInto or AuthPack? */
- if ((kctime != NULL) || (cusec != NULL) || (nonce != NULL) ||
- (pa_cksum != NULL) || (cms_types != NULL)) {
- need_auth_pack = TRUE;
- raw_auth_pack_p = &raw_auth_pack;
- }
- if (need_auth_pack || (cert_status != NULL) ||
- (signer_cert != NULL) || (all_certs != NULL)) {
- proceed = TRUE;
- }
- if (!proceed) {
- krtn = 0;
- goto err_out;
- }
-
- /* Parse and possibly verify the ContentInfo */
- krtn = krb5_pkinit_get_kdc_cert_db(&cert_db);
- if (krtn) {
- pkiDebug("pa_pk_as_req_parse: error in krb5_pkinit_get_kdc_cert_db\n");
- goto err_out;
- }
- krtn = krb5int_pkinit_parse_cms_msg(&signed_auth_pack, cert_db, TRUE,
- &is_signed, &is_encrypted,
- raw_auth_pack_p, &content_type, signer_cert, cert_status,
- num_all_certs, all_certs);
- if (krtn) {
- pkiDebug("krb5int_pkinit_parse_content_info returned %d\n", (int)krtn);
- goto err_out;
- }
-
- if (is_encrypted || !is_signed) {
- pkiDebug("pkinit_parse_content_info: is_encrypted %s is_signed %s!\n",
- is_encrypted ? "true" :"false",
- is_signed ? "true" : "false");
- krtn = KRB5KDC_ERR_PREAUTH_FAILED;
- goto err_out;
- }
- if (content_type != ECT_PkAuthData) {
- pkiDebug("authPack eContentType %d!\n", (int)content_type);
- krtn = KRB5KDC_ERR_PREAUTH_FAILED;
- goto err_out;
- }
-
- /* optionally parse contents of authPack */
- if (need_auth_pack) {
- krtn = krb5int_pkinit_auth_pack_decode(&raw_auth_pack, kctime,
- cusec, nonce, pa_cksum,
- cms_types, num_cms_types);
- if(krtn) {
- pkiDebug("krb5int_pkinit_auth_pack_decode returned %d\n", (int)krtn);
- goto err_out;
- }
- }
-
-err_out:
- /* free temp mallocd data that we didn't pass back to caller */
- if(signed_auth_pack.data) {
- free(signed_auth_pack.data);
- }
- if(raw_auth_pack.data) {
- free(raw_auth_pack.data);
- }
- if(cert_db) {
- krb5_pkinit_release_cert_db(cert_db);
- }
- return krtn;
-}
-
-/*
- * Create a PA-PK-AS-REP message, public key (no Diffie Hellman) version.
- *
- * PA-PK-AS-REP is based on ReplyKeyPack like so:
- *
- * PA-PK-AS-REP ::= EnvelopedData(SignedData(ReplyKeyPack))
- */
-krb5_error_code krb5int_pkinit_as_rep_create(
- krb5_context context,
- const krb5_keyblock *key_block,
- const krb5_checksum *checksum, /* checksum of corresponding AS-REQ */
- krb5_pkinit_signing_cert_t signer_cert, /* server's cert */
- krb5_boolean include_server_cert,/* include signer_cert in SignerInfo */
- const krb5_data *recipient_cert, /* client's cert */
-
- /*
- * These correspond to the same out-parameters from
- * krb5int_pkinit_as_req_parse(). All are optional.
- */
- krb5_ui_4 num_cms_types,
- const krb5int_algorithm_id *cms_types,
- krb5_ui_4 num_trusted_CAs,
- krb5_data *trusted_CAs,
- krb5_data *kdc_cert,
-
- krb5_data *as_rep) /* mallocd and RETURNED */
-{
- krb5_data reply_key_pack = {0, 0, NULL};
- krb5_error_code krtn;
- krb5_data enc_key_pack = {0, 0, NULL};
-
- /* innermost content = ReplyKeyPack */
- krtn = krb5int_pkinit_reply_key_pack_encode(key_block, checksum,
- &reply_key_pack);
- if (krtn) {
- return krtn;
- }
-
- /*
- * Put that in an EnvelopedData(SignedData)
- * -- SignedData.EncapsulatedData.ContentType = id-pkinit-rkeyData
- */
- krtn = krb5int_pkinit_create_cms_msg(&reply_key_pack,
- signer_cert,
- recipient_cert,
- ECT_PkReplyKeyKata,
- num_cms_types, cms_types,
- &enc_key_pack);
- if (krtn) {
- goto err_out;
- }
-
- /*
- * Finally, wrap that inside of PA-PK-AS-REP
- */
- krtn = krb5int_pkinit_pa_pk_as_rep_encode(NULL, &enc_key_pack, as_rep);
-
-err_out:
- if (reply_key_pack.data) {
- free(reply_key_pack.data);
- }
- if (enc_key_pack.data) {
- free(enc_key_pack.data);
- }
- return krtn;
-}
-
-#endif /* APPLE_PKINIT */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_server.h - Server side routines for PKINIT
- *
- * Created 21 May 2004 by Doug Mitchell at Apple.
- */
-
-#ifndef _PKINIT_SERVER_H_
-#define _PKINIT_SERVER_H_
-
-#include "krb5.h"
-#include "pkinit_cms.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
- * Parse PA-PK-AS-REQ message. Optionally evaluates the message's certificate chain
- * if cert_status is non-NULL. Optionally returns various components.
- */
-krb5_error_code krb5int_pkinit_as_req_parse(
- krb5_context context,
- const krb5_data *as_req,
- krb5_timestamp *kctime, /* optionally RETURNED */
- krb5_ui_4 *cusec, /* microseconds, optionally RETURNED */
- krb5_ui_4 *nonce, /* optionally RETURNED */
- krb5_checksum *pa_cksum, /* optional, contents mallocd and RETURNED */
- krb5int_cert_sig_status *cert_status, /* optionally RETURNED */
- krb5_ui_4 *num_cms_types, /* optionally RETURNED */
- krb5int_algorithm_id **cms_types, /* optionally mallocd and RETURNED */
-
- /*
- * Cert fields, all optionally RETURNED.
- *
- * signer_cert is the full X.509 leaf cert from the incoming SignedData.
- * all_certs is an array of all of the certs in the incoming SignedData,
- * in full X.509 form.
- */
- krb5_data *signer_cert, /* content mallocd */
- krb5_ui_4 *num_all_certs, /* sizeof *all_certs */
- krb5_data **all_certs, /* krb5_data's and their content mallocd */
-
- /*
- * Array of trustedCertifiers, optionally RETURNED. These are DER-encoded
- * issuer/serial numbers.
- */
- krb5_ui_4 *num_trusted_CAs, /* sizeof *trustedCAs */
- krb5_data **trusted_CAs, /* krb5_data's and their content mallocd */
-
- /* KDC cert specified by client as kdcPkId. DER-encoded issuer/serial number. */
- krb5_data *kdc_cert);
-
-
-/*
- * Create a PA-PK-AS-REP message, public key (no Diffie Hellman) version.
- *
- * PA-PK-AS-REP is based on ReplyKeyPack like so:
- *
- * PA-PK-AS-REP ::= EnvelopedData(SignedData(ReplyKeyPack))
- */
-krb5_error_code krb5int_pkinit_as_rep_create(
- krb5_context context,
- const krb5_keyblock *key_block,
- const krb5_checksum *checksum, /* checksum of corresponding AS-REQ */
- krb5_pkinit_signing_cert_t signer_cert, /* server's cert */
- krb5_boolean include_server_cert, /* include signer_cert in SignerInfo */
- const krb5_data *recipient_cert, /* client's cert */
-
- /*
- * These correspond to the same out-parameters from
- * krb5int_pkinit_as_req_parse(). All are optional.
- */
- krb5_ui_4 num_cms_types,
- const krb5int_algorithm_id *cms_types,
- krb5_ui_4 num_trusted_CAs,
- krb5_data *trusted_CAs,
- krb5_data *kdc_cert,
-
- /* result here, mallocd and RETURNED */
- krb5_data *as_rep);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PKINIT_SERVER_H_ */
#include "fast.h"
#include "init_creds_ctx.h"
-#if APPLE_PKINIT
-#define IN_TKT_DEBUG 0
-#if IN_TKT_DEBUG
-#define inTktDebug(args...) printf(args)
-#else
-#define inTktDebug(args...)
-#endif
-#endif /* APPLE_PKINIT */
-
/* some typedef's for the function args to make things look a bit cleaner */
static krb5_error_code make_preauth_list (krb5_context,
(request->till != 0) &&
(as_reply->enc_part2->times.renew_till > request->till))
) {
-#if APPLE_PKINIT
- inTktDebug("verify_as_reply: KDCREP_MODIFIED\n");
-#if IN_TKT_DEBUG
- if(request->client->realm.length && request->client->data->length)
- inTktDebug("request: name %s realm %s\n",
- request->client->realm.data, request->client->data->data);
- if(as_reply->client->realm.length && as_reply->client->data->length)
- inTktDebug("reply : name %s realm %s\n",
- as_reply->client->realm.data, as_reply->client->data->data);
-#endif
-#endif /* APPLE_PKINIT */
return KRB5_KDCREP_MODIFIED;
}
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_apple_asn1.c - ASN.1 encode/decode routines for PKINIT, Mac OS X
- * version
- *
- * Created 19 May 2004 by Doug Mitchell.
- */
-
-#if APPLE_PKINIT
-
-#include "k5-int.h"
-#include "pkinit_asn1.h"
-#include "pkinit_apple_utils.h"
-#include <stddef.h>
-#include <Security/SecAsn1Types.h>
-#include <Security/SecAsn1Templates.h>
-#include <Security/SecAsn1Coder.h>
-#include <Security/Security.h>
-#include <sys/errno.h>
-#include <assert.h>
-#include <strings.h>
-
-#pragma mark ----- utility routines -----
-
-/* malloc a NULL-ed array of pointers of size num+1 */
-static void **pkiNssNullArray(
- uint32 num,
- SecAsn1CoderRef coder)
-{
- unsigned len = (num + 1) * sizeof(void *);
- void **p = (void **)SecAsn1Malloc(coder, len);
- memset(p, 0, len);
- return p;
-}
-
-#pragma mark ====== begin PA-PK-AS-REQ components ======
-
-#pragma mark ----- pkAuthenticator -----
-
-/*
- * There is a unique error code for "missing paChecksum", so we mark it here
- * as optional so the decoder can process a pkAuthenticator without the
- * checksum; caller must verify that paChecksum.Data != NULL.
- */
-typedef struct {
- CSSM_DATA cusec; /* INTEGER, microseconds */
- CSSM_DATA kctime; /* UTC time (with trailing 'Z') */
- CSSM_DATA nonce; /* INTEGER */
- CSSM_DATA paChecksum; /* OCTET STRING */
-} KRB5_PKAuthenticator;
-
-static const SecAsn1Template KRB5_PKAuthenticatorTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_PKAuthenticator) },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
- offsetof(KRB5_PKAuthenticator,cusec),
- kSecAsn1IntegerTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 1,
- offsetof(KRB5_PKAuthenticator,kctime),
- kSecAsn1GeneralizedTimeTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 2,
- offsetof(KRB5_PKAuthenticator,nonce),
- kSecAsn1IntegerTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
- SEC_ASN1_OPTIONAL | 3,
- offsetof(KRB5_PKAuthenticator,paChecksum),
- &kSecAsn1OctetStringTemplate },
- { 0 }
-};
-
-#pragma mark ----- AuthPack -----
-
-typedef struct {
- KRB5_PKAuthenticator pkAuth;
- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *pubKeyInfo; /* OPTIONAL */
- CSSM_X509_ALGORITHM_IDENTIFIER **supportedCMSTypes;/* OPTIONAL */
- CSSM_DATA *clientDHNonce; /* OPTIONAL */
-} KRB5_AuthPack;
-
-/*
- * These are copied from keyTemplates.c in the libsecurity_asn1 project;
- * they aren't public API.
- */
-
-/* AlgorithmIdentifier : CSSM_X509_ALGORITHM_IDENTIFIER */
-static const SecAsn1Template AlgorithmIDTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(CSSM_X509_ALGORITHM_IDENTIFIER,algorithm), },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
- offsetof(CSSM_X509_ALGORITHM_IDENTIFIER,parameters), },
- { 0, }
-};
-
-
-/* SubjectPublicKeyInfo : CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */
-static const SecAsn1Template SubjectPublicKeyInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO) },
- { SEC_ASN1_INLINE,
- offsetof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO,algorithm),
- AlgorithmIDTemplate },
- { SEC_ASN1_BIT_STRING,
- offsetof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO,subjectPublicKey), },
- { 0, }
-};
-
-/* end of copied templates */
-
-static const SecAsn1Template kSecAsn1SequenceOfAlgIdTemplate[] = {
- { SEC_ASN1_SEQUENCE_OF, 0, AlgorithmIDTemplate }
-};
-
-static const SecAsn1Template KRB5_AuthPackTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_AuthPack) },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
- offsetof(KRB5_AuthPack,pkAuth),
- KRB5_PKAuthenticatorTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL |
- SEC_ASN1_EXPLICIT | SEC_ASN1_POINTER | 1,
- offsetof(KRB5_AuthPack,pubKeyInfo),
- SubjectPublicKeyInfoTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL |
- SEC_ASN1_EXPLICIT | SEC_ASN1_POINTER | 2,
- offsetof(KRB5_AuthPack,supportedCMSTypes),
- kSecAsn1SequenceOfAlgIdTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL |
- SEC_ASN1_EXPLICIT | SEC_ASN1_POINTER | 3,
- offsetof(KRB5_AuthPack,clientDHNonce),
- kSecAsn1OctetStringTemplate },
- { 0 }
-};
-
-/*
- * Encode AuthPack, public key version (no Diffie-Hellman components).
- */
-krb5_error_code krb5int_pkinit_auth_pack_encode(
- krb5_timestamp kctime,
- krb5_int32 cusec, /* microseconds */
- krb5_ui_4 nonce,
- const krb5_checksum *pa_checksum,
- const krb5int_algorithm_id *cms_types, /* optional */
- krb5_ui_4 num_cms_types,
- krb5_data *auth_pack) /* mallocd and RETURNED */
-{
- KRB5_AuthPack localAuthPack;
- SecAsn1CoderRef coder;
- CSSM_DATA *cksum = &localAuthPack.pkAuth.paChecksum;
- krb5_error_code ourRtn = 0;
- CSSM_DATA ber = {0, NULL};
- OSStatus ortn;
- char *timeStr = NULL;
-
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- memset(&localAuthPack, 0, sizeof(localAuthPack));
- if(pkiKrbTimestampToStr(kctime, &timeStr)) {
- ourRtn = -1;
- goto errOut;
- }
- localAuthPack.pkAuth.kctime.Data = (uint8 *)timeStr;
- localAuthPack.pkAuth.kctime.Length = strlen(timeStr);
- if(pkiIntToData(cusec, &localAuthPack.pkAuth.cusec, coder)) {
- ourRtn = ENOMEM;
- goto errOut;
- }
- if(pkiIntToData(nonce, &localAuthPack.pkAuth.nonce, coder)) {
- ourRtn = ENOMEM;
- goto errOut;
- }
- cksum->Data = (uint8 *)pa_checksum->contents;
- cksum->Length = pa_checksum->length;
-
- if((cms_types != NULL) && (num_cms_types != 0)) {
- unsigned dex;
- CSSM_X509_ALGORITHM_IDENTIFIER **algIds;
-
- /* build a NULL_terminated array of CSSM_X509_ALGORITHM_IDENTIFIERs */
- localAuthPack.supportedCMSTypes = (CSSM_X509_ALGORITHM_IDENTIFIER **)
- SecAsn1Malloc(coder,
- (num_cms_types + 1) * sizeof(CSSM_X509_ALGORITHM_IDENTIFIER *));
- algIds = localAuthPack.supportedCMSTypes;
- for(dex=0; dex<num_cms_types; dex++) {
- algIds[dex] = (CSSM_X509_ALGORITHM_IDENTIFIER *)
- SecAsn1Malloc(coder, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
- pkiKrb5DataToCssm(&cms_types[dex].algorithm,
- &algIds[dex]->algorithm, coder);
- if(cms_types[dex].parameters.data != NULL) {
- pkiKrb5DataToCssm(&cms_types[dex].parameters,
- &algIds[dex]->parameters, coder);
- }
- else {
- algIds[dex]->parameters.Data = NULL;
- algIds[dex]->parameters.Length = 0;
- }
- }
- algIds[num_cms_types] = NULL;
- }
- ortn = SecAsn1EncodeItem(coder, &localAuthPack, KRB5_AuthPackTemplate, &ber);
- if(ortn) {
- ourRtn = ENOMEM;
- goto errOut;
- }
-
- if(pkiCssmDataToKrb5Data(&ber, auth_pack)) {
- ourRtn = ENOMEM;
- }
- else {
- auth_pack->magic = KV5M_AUTHENTICATOR;
- ourRtn = 0;
- }
-errOut:
- SecAsn1CoderRelease(coder);
- return ourRtn;
-}
-
-/*
- * Decode AuthPack, public key version (no Diffie-Hellman components).
- */
-krb5_error_code krb5int_pkinit_auth_pack_decode(
- const krb5_data *auth_pack, /* DER encoded */
- krb5_timestamp *kctime, /* RETURNED */
- krb5_ui_4 *cusec, /* microseconds, RETURNED */
- krb5_ui_4 *nonce, /* RETURNED */
- krb5_checksum *pa_checksum, /* contents mallocd and RETURNED */
- krb5int_algorithm_id **cms_types, /* optionally mallocd and RETURNED */
- krb5_ui_4 *num_cms_types) /* optionally RETURNED */
-{
- KRB5_AuthPack localAuthPack;
- SecAsn1CoderRef coder;
- CSSM_DATA der = {0, NULL};
- krb5_error_code ourRtn = 0;
- CSSM_DATA *cksum = &localAuthPack.pkAuth.paChecksum;
-
- /* Decode --> localAuthPack */
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- PKI_KRB_TO_CSSM_DATA(auth_pack, &der);
- memset(&localAuthPack, 0, sizeof(localAuthPack));
- if(SecAsn1DecodeData(coder, &der, KRB5_AuthPackTemplate, &localAuthPack)) {
- ourRtn = ASN1_BAD_FORMAT;
- goto errOut;
- }
-
- /* optionally Convert KRB5_AuthPack to caller's params */
- if(kctime) {
- if((ourRtn = pkiTimeStrToKrbTimestamp((char *)localAuthPack.pkAuth.kctime.Data,
- localAuthPack.pkAuth.kctime.Length, kctime))) {
- goto errOut;
- }
- }
- if(cusec) {
- if((ourRtn = pkiDataToInt(&localAuthPack.pkAuth.cusec, (krb5_int32 *)cusec))) {
- goto errOut;
- }
- }
- if(nonce) {
- if((ourRtn = pkiDataToInt(&localAuthPack.pkAuth.nonce, (krb5_int32 *)nonce))) {
- goto errOut;
- }
- }
- if(pa_checksum) {
- if(cksum->Length == 0) {
- /* This is the unique error for "no paChecksum" */
- ourRtn = KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
- goto errOut;
- }
- else {
- pa_checksum->contents = (krb5_octet *)malloc(cksum->Length);
- if(pa_checksum->contents == NULL) {
- ourRtn = ENOMEM;
- goto errOut;
- }
- pa_checksum->length = cksum->Length;
- memmove(pa_checksum->contents, cksum->Data, pa_checksum->length);
- pa_checksum->magic = KV5M_CHECKSUM;
- /* This used to be encoded with the checksum but no more... */
- pa_checksum->checksum_type = CKSUMTYPE_NIST_SHA;
- }
- }
- if(cms_types) {
- if(localAuthPack.supportedCMSTypes == NULL) {
- *cms_types = NULL;
- *num_cms_types = 0;
- }
- else {
- /*
- * Convert NULL-terminated array of CSSM-style algIds to
- * krb5int_algorithm_ids.
- */
- unsigned dex;
- unsigned num_types = 0;
- CSSM_X509_ALGORITHM_IDENTIFIER **alg_ids;
- krb5int_algorithm_id *kalg_ids;
-
- for(alg_ids=localAuthPack.supportedCMSTypes;
- *alg_ids;
- alg_ids++) {
- num_types++;
- }
- *cms_types = kalg_ids = (krb5int_algorithm_id *)calloc(num_types,
- sizeof(krb5int_algorithm_id));
- *num_cms_types = num_types;
- alg_ids = localAuthPack.supportedCMSTypes;
- for(dex=0; dex<num_types; dex++) {
- if(alg_ids[dex]->algorithm.Data) {
- pkiCssmDataToKrb5Data(&alg_ids[dex]->algorithm,
- &kalg_ids[dex].algorithm);
- }
- if(alg_ids[dex]->parameters.Data) {
- pkiCssmDataToKrb5Data(&alg_ids[dex]->parameters,
- &kalg_ids[dex].parameters);
- }
- }
- }
- }
- ourRtn = 0;
-errOut:
- SecAsn1CoderRelease(coder);
- return ourRtn;
-}
-
-#pragma mark ----- IssuerAndSerialNumber -----
-
-/*
- * Issuer/serial number - specify issuer as ASN_ANY because we can get it from
- * CL in DER-encoded state.
- */
-typedef struct {
- CSSM_DATA derIssuer;
- CSSM_DATA serialNumber;
-} KRB5_IssuerAndSerial;
-
-static const SecAsn1Template KRB5_IssuerAndSerialTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_IssuerAndSerial) },
- { SEC_ASN1_ANY, offsetof(KRB5_IssuerAndSerial, derIssuer) },
- { SEC_ASN1_INTEGER, offsetof(KRB5_IssuerAndSerial, serialNumber) },
- { 0 }
-};
-
-/*
- * Given DER-encoded issuer and serial number, create an encoded
- * IssuerAndSerialNumber.
- */
-krb5_error_code krb5int_pkinit_issuer_serial_encode(
- const krb5_data *issuer, /* DER encoded */
- const krb5_data *serial_num,
- krb5_data *issuer_and_serial) /* content mallocd and RETURNED */
-{
- KRB5_IssuerAndSerial issuerSerial;
- SecAsn1CoderRef coder;
- CSSM_DATA ber = {0, NULL};
- OSStatus ortn;
-
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- PKI_KRB_TO_CSSM_DATA(issuer, &issuerSerial.derIssuer);
- PKI_KRB_TO_CSSM_DATA(serial_num, &issuerSerial.serialNumber);
- ortn = SecAsn1EncodeItem(coder, &issuerSerial, KRB5_IssuerAndSerialTemplate, &ber);
- if(ortn) {
- ortn = ENOMEM;
- goto errOut;
- }
- ortn = pkiCssmDataToKrb5Data(&ber, issuer_and_serial);
-errOut:
- SecAsn1CoderRelease(coder);
- return ortn;
-}
-
-/*
- * Decode IssuerAndSerialNumber.
- */
-krb5_error_code krb5int_pkinit_issuer_serial_decode(
- const krb5_data *issuer_and_serial, /* DER encoded */
- krb5_data *issuer, /* DER encoded, RETURNED */
- krb5_data *serial_num) /* RETURNED */
-{
- KRB5_IssuerAndSerial issuerSerial;
- SecAsn1CoderRef coder;
- CSSM_DATA der = {issuer_and_serial->length, (uint8 *)issuer_and_serial->data};
- krb5_error_code ourRtn = 0;
-
- /* Decode --> issuerSerial */
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- memset(&issuerSerial, 0, sizeof(issuerSerial));
- if(SecAsn1DecodeData(coder, &der, KRB5_IssuerAndSerialTemplate, &issuerSerial)) {
- ourRtn = ASN1_BAD_FORMAT;
- goto errOut;
- }
-
- /* Convert KRB5_IssuerAndSerial to caller's params */
- if((ourRtn = pkiCssmDataToKrb5Data(&issuerSerial.derIssuer, issuer))) {
- goto errOut;
- }
- if((ourRtn = pkiCssmDataToKrb5Data(&issuerSerial.serialNumber, serial_num))) {
- ourRtn = ENOMEM;
- goto errOut;
- }
-
-errOut:
- SecAsn1CoderRelease(coder);
- return ourRtn;
-}
-
-#pragma mark ----- ExternalPrincipalIdentifier -----
-
-/*
- * Shown here for completeness; this module only implements the
- * issuerAndSerialNumber option.
- */
-typedef struct {
- CSSM_DATA subjectName; /* [0] IMPLICIT OCTET STRING OPTIONAL */
- /* contents = encoded Name */
- CSSM_DATA issuerAndSerialNumber; /* [1] IMPLICIT OCTET STRING OPTIONAL */
- /* contents = encoded Issuer&Serial */
- CSSM_DATA subjectKeyIdentifier; /* [2] IMPLICIT OCTET STRING OPTIONAL */
- /* contents = encoded subjectKeyIdentifier extension */
-} KRB5_ExternalPrincipalIdentifier;
-
-static const SecAsn1Template KRB5_ExternalPrincipalIdentifierTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_ExternalPrincipalIdentifier) },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL | 0,
- offsetof(KRB5_ExternalPrincipalIdentifier, subjectName),
- kSecAsn1OctetStringTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL | 1,
- offsetof(KRB5_ExternalPrincipalIdentifier, issuerAndSerialNumber),
- kSecAsn1OctetStringTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_OPTIONAL | 2,
- offsetof(KRB5_ExternalPrincipalIdentifier, subjectKeyIdentifier),
- kSecAsn1OctetStringTemplate },
- { 0 }
-};
-
-static const SecAsn1Template KRB5_SequenceOfExternalPrincipalIdentifierTemplate[] = {
- { SEC_ASN1_SEQUENCE_OF, 0, KRB5_ExternalPrincipalIdentifierTemplate }
-};
-
-#pragma mark ----- PA-PK-AS-REQ -----
-
-/*
- * Top-level PA-PK-AS-REQ. All fields except for trusted_CAs are pre-encoded
- * before we encode this and are still DER-encoded after we decode.
- * The signedAuthPack and kdcPkId fields are wrapped in OCTET STRINGs
- * during encode; we strip off the OCTET STRING wrappers during decode.
- */
-typedef struct {
- CSSM_DATA signedAuthPack; /* ContentInfo, SignedData */
- /* Content is KRB5_AuthPack */
- KRB5_ExternalPrincipalIdentifier
- **trusted_CAs; /* optional */
- CSSM_DATA kdcPkId; /* optional */
-} KRB5_PA_PK_AS_REQ;
-
-static const SecAsn1Template KRB5_PA_PK_AS_REQTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_PA_PK_AS_REQ) },
- { SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(KRB5_PA_PK_AS_REQ, signedAuthPack),
- kSecAsn1OctetStringTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
- SEC_ASN1_EXPLICIT | 1,
- offsetof(KRB5_PA_PK_AS_REQ, trusted_CAs),
- KRB5_SequenceOfExternalPrincipalIdentifierTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 2,
- offsetof(KRB5_PA_PK_AS_REQ, kdcPkId),
- kSecAsn1AnyTemplate },
- { 0 }
-};
-
-/*
- * Top-level encode for PA-PK-AS-REQ.
- */
-krb5_error_code krb5int_pkinit_pa_pk_as_req_encode(
- const krb5_data *signed_auth_pack, /* DER encoded ContentInfo */
- const krb5_data *trusted_CAs, /* optional: trustedCertifiers. Contents are
- * DER-encoded issuer/serialNumbers. */
- krb5_ui_4 num_trusted_CAs,
- const krb5_data *kdc_cert, /* optional kdcPkId, DER encoded issuer/serial */
- krb5_data *pa_pk_as_req) /* mallocd and RETURNED */
-{
- KRB5_PA_PK_AS_REQ req;
- SecAsn1CoderRef coder;
- CSSM_DATA ber = {0, NULL};
- OSStatus ortn;
- unsigned dex;
-
- assert(signed_auth_pack != NULL);
- assert(pa_pk_as_req != NULL);
-
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
-
- /* krb5_data ==> CSSM format */
-
- memset(&req, 0, sizeof(req));
- PKI_KRB_TO_CSSM_DATA(signed_auth_pack, &req.signedAuthPack);
- if(num_trusted_CAs) {
- /*
- * Set up a NULL-terminated array of KRB5_ExternalPrincipalIdentifier
- * pointers. We malloc the actual KRB5_ExternalPrincipalIdentifiers as
- * a contiguous array; it's in temp SecAsn1CoderRef memory. The referents
- * are just dropped in from the caller's krb5_datas.
- */
- KRB5_ExternalPrincipalIdentifier *cas =
- (KRB5_ExternalPrincipalIdentifier *)SecAsn1Malloc(coder,
- num_trusted_CAs * sizeof(KRB5_ExternalPrincipalIdentifier));
- req.trusted_CAs =
- (KRB5_ExternalPrincipalIdentifier **)
- pkiNssNullArray(num_trusted_CAs, coder);
- for(dex=0; dex<num_trusted_CAs; dex++) {
- req.trusted_CAs[dex] = &cas[dex];
- memset(&cas[dex], 0, sizeof(KRB5_ExternalPrincipalIdentifier));
- PKI_KRB_TO_CSSM_DATA(&trusted_CAs[dex],
- &cas[dex].issuerAndSerialNumber);
- }
- }
- if(kdc_cert) {
- PKI_KRB_TO_CSSM_DATA(kdc_cert, &req.kdcPkId);
- }
-
- /* encode */
- ortn = SecAsn1EncodeItem(coder, &req, KRB5_PA_PK_AS_REQTemplate, &ber);
- if(ortn) {
- ortn = ENOMEM;
- goto errOut;
- }
- ortn = pkiCssmDataToKrb5Data(&ber, pa_pk_as_req);
-
-errOut:
- SecAsn1CoderRelease(coder);
- return ortn;
-}
-
-/*
- * Top-level decode for PA-PK-AS-REQ.
- */
-krb5_error_code krb5int_pkinit_pa_pk_as_req_decode(
- const krb5_data *pa_pk_as_req,
- krb5_data *signed_auth_pack, /* DER encoded ContentInfo, RETURNED */
- /*
- * Remainder are optionally RETURNED (specify NULL for pointers to
- * items you're not interested in).
- */
- krb5_ui_4 *num_trusted_CAs, /* sizeof trusted_CAs */
- krb5_data **trusted_CAs, /* mallocd array of DER-encoded TrustedCAs issuer/serial */
- krb5_data *kdc_cert) /* DER encoded issuer/serial */
-{
- KRB5_PA_PK_AS_REQ asReq;
- SecAsn1CoderRef coder;
- CSSM_DATA der;
- krb5_error_code ourRtn = 0;
-
- assert(pa_pk_as_req != NULL);
-
- /* Decode --> KRB5_PA_PK_AS_REQ */
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- PKI_KRB_TO_CSSM_DATA(pa_pk_as_req, &der);
- memset(&asReq, 0, sizeof(asReq));
- if(SecAsn1DecodeData(coder, &der, KRB5_PA_PK_AS_REQTemplate, &asReq)) {
- ourRtn = ASN1_BAD_FORMAT;
- goto errOut;
- }
-
- /* Convert decoded results to caller's args; each is optional */
- if(signed_auth_pack != NULL) {
- if((ourRtn = pkiCssmDataToKrb5Data(&asReq.signedAuthPack, signed_auth_pack))) {
- goto errOut;
- }
- }
- if(asReq.trusted_CAs && (trusted_CAs != NULL)) {
- /* NULL-terminated array of CSSM_DATA ptrs */
- unsigned numCas = pkiNssArraySize((const void **)asReq.trusted_CAs);
- unsigned dex;
- krb5_data *kdcCas;
-
- kdcCas = (krb5_data *)malloc(sizeof(krb5_data) * numCas);
- if(kdcCas == NULL) {
- ourRtn = ENOMEM;
- goto errOut;
- }
- for(dex=0; dex<numCas; dex++) {
- KRB5_ExternalPrincipalIdentifier *epi = asReq.trusted_CAs[dex];
- if(epi->issuerAndSerialNumber.Data) {
- /* the only variant we support */
- pkiCssmDataToKrb5Data(&epi->issuerAndSerialNumber, &kdcCas[dex]);
- }
- }
- *trusted_CAs = kdcCas;
- *num_trusted_CAs = numCas;
- }
- if(asReq.kdcPkId.Data && kdc_cert) {
- if((ourRtn = pkiCssmDataToKrb5Data(&asReq.kdcPkId, kdc_cert))) {
- goto errOut;
- }
- }
-errOut:
- SecAsn1CoderRelease(coder);
- return ourRtn;
-}
-
-#pragma mark ====== begin PA-PK-AS-REP components ======
-
-typedef struct {
- CSSM_DATA subjectPublicKey; /* BIT STRING */
- CSSM_DATA nonce; /* from KRB5_PKAuthenticator.nonce */
- CSSM_DATA *expiration; /* optional UTC time */
-} KRB5_KDC_DHKeyInfo;
-
-typedef struct {
- CSSM_DATA keyType;
- CSSM_DATA keyValue;
-} KRB5_EncryptionKey;
-
-static const SecAsn1Template KRB5_EncryptionKeyTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_EncryptionKey) },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
- offsetof(KRB5_EncryptionKey, keyType),
- kSecAsn1IntegerTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 1,
- offsetof(KRB5_EncryptionKey, keyValue),
- kSecAsn1OctetStringTemplate },
- { 0 }
-};
-
-#pragma mark ----- Checksum -----
-
-typedef struct {
- CSSM_DATA checksumType;
- CSSM_DATA checksum;
-} KRB5_Checksum;
-
-static const SecAsn1Template KRB5_ChecksumTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_Checksum) },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
- offsetof(KRB5_Checksum,checksumType),
- kSecAsn1IntegerTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 1,
- offsetof(KRB5_Checksum,checksum),
- kSecAsn1OctetStringTemplate },
- { 0 }
-};
-
-typedef struct {
- KRB5_EncryptionKey encryptionKey;
- KRB5_Checksum asChecksum;
-} KRB5_ReplyKeyPack;
-
-static const SecAsn1Template KRB5_ReplyKeyPackTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_ReplyKeyPack) },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
- offsetof(KRB5_ReplyKeyPack, encryptionKey),
- KRB5_EncryptionKeyTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 1,
- offsetof(KRB5_ReplyKeyPack,asChecksum),
- KRB5_ChecksumTemplate },
- { 0 }
-};
-
-/*
- * Encode a ReplyKeyPack. The result is used as the Content of a SignedData.
- */
-krb5_error_code krb5int_pkinit_reply_key_pack_encode(
- const krb5_keyblock *key_block,
- const krb5_checksum *checksum,
- krb5_data *reply_key_pack) /* mallocd and RETURNED */
-{
- KRB5_ReplyKeyPack repKeyPack;
- SecAsn1CoderRef coder;
- krb5_error_code ourRtn = 0;
- CSSM_DATA der = {0, NULL};
- OSStatus ortn;
- KRB5_EncryptionKey *encryptKey = &repKeyPack.encryptionKey;
- KRB5_Checksum *cksum = &repKeyPack.asChecksum;
-
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- memset(&repKeyPack, 0, sizeof(repKeyPack));
-
- if((ourRtn = pkiIntToData(key_block->enctype, &encryptKey->keyType, coder))) {
- goto errOut;
- }
- encryptKey->keyValue.Length = key_block->length,
- encryptKey->keyValue.Data = (uint8 *)key_block->contents;
-
- if((ourRtn = pkiIntToData(checksum->checksum_type, &cksum->checksumType, coder))) {
- goto errOut;
- }
- cksum->checksum.Data = (uint8 *)checksum->contents;
- cksum->checksum.Length = checksum->length;
-
- ortn = SecAsn1EncodeItem(coder, &repKeyPack, KRB5_ReplyKeyPackTemplate, &der);
- if(ortn) {
- ourRtn = ENOMEM;
- goto errOut;
- }
- ourRtn = pkiCssmDataToKrb5Data(&der, reply_key_pack);
-errOut:
- SecAsn1CoderRelease(coder);
- return ourRtn;
-}
-
-/*
- * Decode a ReplyKeyPack.
- */
-krb5_error_code krb5int_pkinit_reply_key_pack_decode(
- const krb5_data *reply_key_pack,
- krb5_keyblock *key_block, /* RETURNED */
- krb5_checksum *checksum) /* contents mallocd and RETURNED */
-{
- KRB5_ReplyKeyPack repKeyPack;
- SecAsn1CoderRef coder;
- krb5_error_code ourRtn = 0;
- KRB5_EncryptionKey *encryptKey = &repKeyPack.encryptionKey;
- CSSM_DATA der = {reply_key_pack->length, (uint8 *)reply_key_pack->data};
- krb5_data tmpData;
- KRB5_Checksum *cksum = &repKeyPack.asChecksum;
-
- /* Decode --> KRB5_ReplyKeyPack */
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- memset(&repKeyPack, 0, sizeof(repKeyPack));
- if(SecAsn1DecodeData(coder, &der, KRB5_ReplyKeyPackTemplate, &repKeyPack)) {
- ourRtn = ASN1_BAD_FORMAT;
- goto errOut;
- }
-
- if((ourRtn = pkiDataToInt(&encryptKey->keyType, (krb5_int32 *)&key_block->enctype))) {
- goto errOut;
- }
- if((ourRtn = pkiCssmDataToKrb5Data(&encryptKey->keyValue, &tmpData))) {
- goto errOut;
- }
- key_block->contents = (krb5_octet *)tmpData.data;
- key_block->length = tmpData.length;
-
- if((ourRtn = pkiDataToInt(&cksum->checksumType, &checksum->checksum_type))) {
- goto errOut;
- }
- checksum->contents = (krb5_octet *)malloc(cksum->checksum.Length);
- if(checksum->contents == NULL) {
- ourRtn = ENOMEM;
- goto errOut;
- }
- checksum->length = cksum->checksum.Length;
- memmove(checksum->contents, cksum->checksum.Data, checksum->length);
- checksum->magic = KV5M_CHECKSUM;
-
-errOut:
- SecAsn1CoderRelease(coder);
- return ourRtn;
-}
-
-
-#pragma mark ----- KRB5_PA_PK_AS_REP -----
-/*
- * Top-level PA-PK-AS-REP. Exactly one of the optional fields must be present.
- */
-typedef struct {
- CSSM_DATA *dhSignedData; /* ContentInfo, SignedData */
- /* Content is KRB5_KDC_DHKeyInfo */
- CSSM_DATA *encKeyPack; /* ContentInfo, SignedData */
- /* Content is ReplyKeyPack */
-} KRB5_PA_PK_AS_REP;
-
-static const SecAsn1Template KRB5_PA_PK_AS_REPTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(KRB5_PA_PK_AS_REP) },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL |
- SEC_ASN1_EXPLICIT | 0,
- offsetof(KRB5_PA_PK_AS_REP, dhSignedData),
- kSecAsn1PointerToAnyTemplate },
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL |
- SEC_ASN1_EXPLICIT | 1,
- offsetof(KRB5_PA_PK_AS_REP, encKeyPack),
- kSecAsn1PointerToAnyTemplate },
- { 0 }
-};
-
-/*
- * Encode a KRB5_PA_PK_AS_REP.
- */
-krb5_error_code krb5int_pkinit_pa_pk_as_rep_encode(
- const krb5_data *dh_signed_data,
- const krb5_data *enc_key_pack,
- krb5_data *pa_pk_as_rep) /* mallocd and RETURNED */
-{
- KRB5_PA_PK_AS_REP asRep;
- SecAsn1CoderRef coder;
- krb5_error_code ourRtn = 0;
- CSSM_DATA der = {0, NULL};
- OSStatus ortn;
- CSSM_DATA dhSignedData;
- CSSM_DATA encKeyPack;
-
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- memset(&asRep, 0, sizeof(asRep));
- if(dh_signed_data) {
- PKI_KRB_TO_CSSM_DATA(dh_signed_data, &dhSignedData);
- asRep.dhSignedData = &dhSignedData;
- }
- if(enc_key_pack) {
- PKI_KRB_TO_CSSM_DATA(enc_key_pack, &encKeyPack);
- asRep.encKeyPack = &encKeyPack;
- }
-
- ortn = SecAsn1EncodeItem(coder, &asRep, KRB5_PA_PK_AS_REPTemplate, &der);
- if(ortn) {
- ourRtn = ENOMEM;
- goto errOut;
- }
- ourRtn = pkiCssmDataToKrb5Data(&der, pa_pk_as_rep);
-
-errOut:
- SecAsn1CoderRelease(coder);
- return ourRtn;
-}
-
-/*
- * Decode a KRB5_PA_PK_AS_REP.
- */
-krb5_error_code krb5int_pkinit_pa_pk_as_rep_decode(
- const krb5_data *pa_pk_as_rep,
- krb5_data *dh_signed_data,
- krb5_data *enc_key_pack)
-{
- KRB5_PA_PK_AS_REP asRep;
- SecAsn1CoderRef coder;
- CSSM_DATA der = {pa_pk_as_rep->length, (uint8 *)pa_pk_as_rep->data};
- krb5_error_code ourRtn = 0;
-
- /* Decode --> KRB5_PA_PK_AS_REP */
- if(SecAsn1CoderCreate(&coder)) {
- return ENOMEM;
- }
- memset(&asRep, 0, sizeof(asRep));
- if(SecAsn1DecodeData(coder, &der, KRB5_PA_PK_AS_REPTemplate, &asRep)) {
- ourRtn = ASN1_BAD_FORMAT;
- goto errOut;
- }
-
- if(asRep.dhSignedData) {
- if((ourRtn = pkiCssmDataToKrb5Data(asRep.dhSignedData, dh_signed_data))) {
- goto errOut;
- }
- }
- if(asRep.encKeyPack) {
- ourRtn = pkiCssmDataToKrb5Data(asRep.encKeyPack, enc_key_pack);
- }
-
-errOut:
- SecAsn1CoderRelease(coder);
- return ourRtn;
-}
-
-#pragma mark ====== General utilities ======
-
-/*
- * Given a DER encoded certificate, obtain the associated IssuerAndSerialNumber.
- */
-krb5_error_code krb5int_pkinit_get_issuer_serial(
- const krb5_data *cert,
- krb5_data *issuer_and_serial)
-{
- CSSM_HANDLE cacheHand = 0;
- CSSM_RETURN crtn = CSSM_OK;
- CSSM_DATA certData = { cert->length, (uint8 *)cert->data };
- CSSM_HANDLE resultHand = 0;
- CSSM_DATA_PTR derIssuer = NULL;
- CSSM_DATA_PTR serial;
- krb5_data krb_serial;
- krb5_data krb_issuer;
- uint32 numFields;
- krb5_error_code ourRtn = 0;
-
- CSSM_CL_HANDLE clHand = pkiClStartup();
- if(clHand == 0) {
- return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
- }
- /* subsequent errors to errOut: */
-
- crtn = CSSM_CL_CertCache(clHand, &certData, &cacheHand);
- if(crtn) {
- pkiCssmErr("CSSM_CL_CertCache", crtn);
- ourRtn = ASN1_PARSE_ERROR;
- goto errOut;
- }
-
- /* obtain the two fields; issuer is DER encoded */
- crtn = CSSM_CL_CertGetFirstCachedFieldValue(clHand, cacheHand,
- &CSSMOID_X509V1IssuerNameStd, &resultHand, &numFields, &derIssuer);
- if(crtn) {
- pkiCssmErr("CSSM_CL_CertGetFirstCachedFieldValue(issuer)", crtn);
- ourRtn = ASN1_PARSE_ERROR;
- goto errOut;
- }
- crtn = CSSM_CL_CertGetFirstCachedFieldValue(clHand, cacheHand,
- &CSSMOID_X509V1SerialNumber, &resultHand, &numFields, &serial);
- if(crtn) {
- pkiCssmErr("CSSM_CL_CertGetFirstCachedFieldValue(serial)", crtn);
- ourRtn = ASN1_PARSE_ERROR;
- goto errOut;
- }
- PKI_CSSM_TO_KRB_DATA(derIssuer, &krb_issuer);
- PKI_CSSM_TO_KRB_DATA(serial, &krb_serial);
- ourRtn = krb5int_pkinit_issuer_serial_encode(&krb_issuer, &krb_serial, issuer_and_serial);
-
-errOut:
- if(derIssuer) {
- CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1IssuerNameStd, derIssuer);
- }
- if(serial) {
- CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SerialNumber, serial);
- }
- if(cacheHand) {
- CSSM_CL_CertAbortCache(clHand, cacheHand);
- }
- if(clHand) {
- pkiClDetachUnload(clHand);
- }
- return ourRtn;
-}
-
-#endif /* APPLE_PKINIT */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_apple_cert_store.c - PKINIT certificate storage/retrieval utilities,
- * MAC OS X version
- *
- * Created 26 May 2004 by Doug Mitchell at Apple.
- */
-
-#if APPLE_PKINIT
-
-#include "pkinit_cert_store.h"
-#include "pkinit_asn1.h"
-#include "pkinit_apple_utils.h"
-#include <CoreFoundation/CFString.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-#include <assert.h>
-#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
-#include <CommonCrypto/CommonDigest.h>
-#include <sys/errno.h>
-
-/*
- * Client cert info is stored in preferences with this following parameters:
- *
- * key = kPkinitClientCertKey
- * appID = kPkinitClientCertApp
- * username = kCFPreferencesCurrentUser
- * hostname = kCFPreferencesAnyHost
- *
- * The stored property list is a CFDictionary. Keys in the dictionary are
- * principal names (e.g. foobar@REALM.LOCAL).
- *
- * Values in the dictionary are raw data containing the DER-encoded issuer and
- * serial number of the certificate.
- *
- * When obtaining a PKINIT cert, if an entry in the CFDictionary for the specified
- * principal is not found, the entry for the default will be used if it's there.
- */
-
-/*
- * NOTE: ANSI C code requires an Apple-Custom -fconstant-cfstrings CFLAGS to
- * use CFSTR in a const declaration so we just declare the C strings here.
- */
-#define kPkinitClientCertKey "KRBClientCert"
-#define kPkinitClientCertApp "edu.mit.Kerberos.pkinit"
-
-/*
- * KDC cert stored in this keychain. It's linked to systemkeychain so that if
- * a root process tries to unlock it, it auto-unlocks.
- */
-#define KDC_KEYCHAIN "/var/db/krb5kdc/kdc.keychain"
-
-/*
- * Given a certificate, obtain the DER-encoded issuer and serial number. Result
- * is mallocd and must be freed by caller.
- */
-static OSStatus pkinit_get_cert_issuer_sn(
- SecCertificateRef certRef,
- CSSM_DATA *issuerSerial) /* mallocd and RETURNED */
-{
- OSStatus ortn;
- CSSM_DATA certData;
- krb5_data INIT_KDATA(issuerSerialKrb);
- krb5_data certDataKrb;
- krb5_error_code krtn;
-
- assert(certRef != NULL);
- assert(issuerSerial != NULL);
-
- ortn = SecCertificateGetData(certRef, &certData);
- if(ortn) {
- pkiCssmErr("SecCertificateGetData", ortn);
- return ortn;
- }
- PKI_CSSM_TO_KRB_DATA(&certData, &certDataKrb);
- krtn = krb5int_pkinit_get_issuer_serial(&certDataKrb, &issuerSerialKrb);
- if(krtn) {
- return CSSMERR_CL_INVALID_DATA;
- }
- PKI_KRB_TO_CSSM_DATA(&issuerSerialKrb, issuerSerial);
- return noErr;
-}
-
-/*
- * Determine if specified identity's cert's issuer and serial number match the
- * provided issuer and serial number. Returns nonzero on match, else returns zero.
- */
-static int pkinit_issuer_sn_match(
- SecIdentityRef idRef,
- const CSSM_DATA *matchIssuerSerial)
-{
- OSStatus ortn;
- SecCertificateRef certRef = NULL;
- CSSM_DATA INIT_CDATA(certIssuerSerial);
- int ourRtn = 0;
-
- assert(idRef != NULL);
- assert(matchIssuerSerial != NULL);
-
- /* Get this cert's issuer/serial number */
- ortn = SecIdentityCopyCertificate(idRef, &certRef);
- if(ortn) {
- pkiCssmErr("SecIdentityCopyCertificate", ortn);
- return 0;
- }
- /* subsequent errors to errOut: */
- ortn = pkinit_get_cert_issuer_sn(certRef, &certIssuerSerial);
- if(ortn) {
- pkiCssmErr("SecIdentityCopyCertificate", ortn);
- goto errOut;
- }
- ourRtn = pkiCompareCssmData(matchIssuerSerial, &certIssuerSerial) ? 1 : 0;
-errOut:
- if(certRef != NULL) {
- CFRelease(certRef);
- }
- if(certIssuerSerial.Data != NULL) {
- free(certIssuerSerial.Data);
- }
- return ourRtn;
-}
-
-/*
- * Search specified keychain/array/NULL (NULL meaning the default search list) for
- * an Identity matching specified key usage and optional Issuer/Serial number.
- * If issuer/serial is specified and no identities match, or if no identities found
- * matching specified Key usage, errSecItemNotFound is returned.
- *
- * Caller must CFRelease a non-NULL returned idRef.
- */
-static OSStatus pkinit_search_ident(
- CFTypeRef keychainOrArray,
- CSSM_KEYUSE keyUsage,
- const CSSM_DATA *issuerSerial, /* optional */
- SecIdentityRef *foundId) /* RETURNED */
-{
- OSStatus ortn;
- SecIdentityRef idRef = NULL;
- SecIdentitySearchRef srchRef = NULL;
-
- ortn = SecIdentitySearchCreate(keychainOrArray, keyUsage, &srchRef);
- if(ortn) {
- pkiCssmErr("SecIdentitySearchCreate", ortn);
- return ortn;
- }
- do {
- ortn = SecIdentitySearchCopyNext(srchRef, &idRef);
- if(ortn != noErr) {
- break;
- }
- if(issuerSerial == NULL) {
- /* no match needed, we're done - this is the KDC cert case */
- break;
- }
- else if(pkinit_issuer_sn_match(idRef, issuerSerial)) {
- /* match, we're done */
- break;
- }
- /* finished with this one */
- CFRelease(idRef);
- idRef = NULL;
- } while(ortn == noErr);
-
- CFRelease(srchRef);
- if(idRef == NULL) {
- return errSecItemNotFound;
- }
- else {
- *foundId = idRef;
- return noErr;
- }
-}
-
-/*
- * In Mac OS terms, get the keychain on which a given identity resides.
- */
-static krb5_error_code pkinit_cert_to_db(
- krb5_pkinit_signing_cert_t idRef,
- krb5_pkinit_cert_db_t *dbRef)
-{
- SecKeychainRef kcRef = NULL;
- SecKeyRef keyRef = NULL;
- OSStatus ortn;
-
- /* that's an identity - get the associated key's keychain */
- ortn = SecIdentityCopyPrivateKey((SecIdentityRef)idRef, &keyRef);
- if(ortn) {
- pkiCssmErr("SecIdentityCopyPrivateKey", ortn);
- return ortn;
- }
- ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef);
- if(ortn) {
- pkiCssmErr("SecKeychainItemCopyKeychain", ortn);
- }
- else {
- *dbRef = (krb5_pkinit_cert_db_t)kcRef;
- }
- CFRelease(keyRef);
- return ortn;
-}
-
-/*
- * Obtain the CFDictionary representing this user's PKINIT client cert prefs, if it
- * exists. Returns noErr or errSecItemNotFound as appropriate.
- */
-static OSStatus pkinit_get_pref_dict(
- CFDictionaryRef *dict)
-{
- CFDictionaryRef theDict;
- theDict = (CFDictionaryRef)CFPreferencesCopyValue(CFSTR(kPkinitClientCertKey),
- CFSTR(kPkinitClientCertApp), kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
- if(theDict == NULL) {
- pkiDebug("pkinit_get_pref_dict: no kPkinitClientCertKey\n");
- return errSecItemNotFound;
- }
- if(CFGetTypeID(theDict) != CFDictionaryGetTypeID()) {
- pkiDebug("pkinit_get_pref_dict: bad kPkinitClientCertKey pref\n");
- CFRelease(theDict);
- return errSecItemNotFound;
- }
- *dict = theDict;
- return noErr;
-}
-
-#pragma mark --- Public client side functions ---
-
-/*
- * Obtain signing cert for specified principal. On successful return,
- * caller must eventually release the cert with krb5_pkinit_release_cert().
- */
-krb5_error_code krb5_pkinit_get_client_cert(
- const char *principal, /* full principal string */
- krb5_pkinit_signing_cert_t *client_cert)
-{
- CFDataRef issuerSerial = NULL;
- CSSM_DATA issuerSerialData;
- SecIdentityRef idRef = NULL;
- OSStatus ortn;
- CFDictionaryRef theDict = NULL;
- CFStringRef cfPrinc = NULL;
- krb5_error_code ourRtn = 0;
-
- if(principal == NULL) {
- return KRB5_PRINC_NOMATCH;
- }
-
- /* Is there a stored preference for PKINIT certs for this user? */
- ortn = pkinit_get_pref_dict(&theDict);
- if(ortn) {
- return KRB5_PRINC_NOMATCH;
- }
-
- /* Entry in the dictionary for specified principal? */
- cfPrinc = CFStringCreateWithCString(NULL, principal,
- kCFStringEncodingASCII);
- issuerSerial = (CFDataRef)CFDictionaryGetValue(theDict, cfPrinc);
- CFRelease(cfPrinc);
- if(issuerSerial == NULL) {
- pkiDebug("krb5_pkinit_get_client_cert: no identity found\n");
- ourRtn = KRB5_PRINC_NOMATCH;
- goto errOut;
- }
- if(CFGetTypeID(issuerSerial) != CFDataGetTypeID()) {
- pkiDebug("krb5_pkinit_get_client_cert: bad kPkinitClientCertKey value\n");
- ourRtn = KRB5_PRINC_NOMATCH;
- goto errOut;
- }
-
- issuerSerialData.Data = (uint8 *)CFDataGetBytePtr(issuerSerial);
- issuerSerialData.Length = CFDataGetLength(issuerSerial);
-
- /* find a cert with that issuer/serial number in default search list */
- ortn = pkinit_search_ident(NULL, CSSM_KEYUSE_SIGN | CSSM_KEYUSE_ENCRYPT,
- &issuerSerialData, &idRef);
- if(ortn) {
- pkiDebug("krb5_pkinit_get_client_cert: no identity found!\n");
- pkiCssmErr("pkinit_search_ident", ortn);
- ourRtn = KRB5_PRINC_NOMATCH;
- }
- else {
- *client_cert = (krb5_pkinit_signing_cert_t)idRef;
- }
-errOut:
- if(theDict) {
- CFRelease(theDict);
- }
- return ourRtn;
-}
-
-/*
- * Determine if the specified client has a signing cert. Returns TRUE
- * if so, else returns FALSE.
- */
-krb5_boolean krb5_pkinit_have_client_cert(
- const char *principal) /* full principal string */
-{
- krb5_pkinit_signing_cert_t signing_cert = NULL;
- krb5_error_code krtn;
-
- krtn = krb5_pkinit_get_client_cert(principal, &signing_cert);
- if(krtn) {
- return FALSE;
- }
- if(signing_cert != NULL) {
- krb5_pkinit_release_cert(signing_cert);
- return TRUE;
- }
- else {
- return FALSE;
- }
-}
-
-/*
- * Store the specified certificate (or, more likely, some platform-dependent
- * reference to it) as the specified principal's signing certificate. Passing
- * in NULL for the client_cert has the effect of deleting the relevant entry
- * in the cert storage.
- */
-krb5_error_code krb5_pkinit_set_client_cert_from_signing_cert(
- const char *principal, /* full principal string */
- krb5_pkinit_signing_cert_t client_cert)
-{
- SecIdentityRef idRef = (SecIdentityRef)client_cert;
- SecCertificateRef certRef = NULL;
- OSStatus ortn;
- krb5_error_code ourRtn = 0;
-
- if (NULL != idRef) {
- if (CFGetTypeID(idRef) != SecIdentityGetTypeID()) {
- ourRtn = KRB5KRB_ERR_GENERIC;
- goto fin;
- }
- /* Get the cert */
- ortn = SecIdentityCopyCertificate(idRef, &certRef);
- if (ortn) {
- pkiCssmErr("SecIdentityCopyCertificate", ortn);
- ourRtn = KRB5KRB_ERR_GENERIC;
- goto fin;
- }
- }
- ourRtn = krb5_pkinit_set_client_cert(principal, (krb5_pkinit_cert_t)certRef);
-fin:
- if (certRef)
- CFRelease(certRef);
- return ourRtn;
-}
-
-
-/*
- * Store the specified certificate (or, more likely, some platform-dependent
- * reference to it) as the specified principal's certificate. Passing
- * in NULL for the client_cert has the effect of deleting the relevant entry
- * in the cert storage.
- */
-krb5_error_code krb5_pkinit_set_client_cert(
- const char *principal, /* full principal string */
- krb5_pkinit_cert_t client_cert)
-{
- SecCertificateRef certRef = (SecCertificateRef)client_cert;
- OSStatus ortn;
- CSSM_DATA issuerSerial = {0, NULL};
- CFDataRef cfIssuerSerial = NULL;
- CFDictionaryRef existDict = NULL;
- CFMutableDictionaryRef newDict = NULL;
- CFStringRef keyStr = NULL;
- krb5_error_code ourRtn = 0;
-
- if(certRef != NULL) {
- if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) {
- return KRB5KRB_ERR_GENERIC;
- }
-
- /* Cook up DER-encoded issuer/serial number */
- ortn = pkinit_get_cert_issuer_sn(certRef, &issuerSerial);
- if(ortn) {
- ourRtn = KRB5KRB_ERR_GENERIC;
- goto errOut;
- }
- }
-
- /*
- * Obtain the existing pref for kPkinitClientCertKey as a CFDictionary, or
- * cook up a new one.
- */
- ortn = pkinit_get_pref_dict(&existDict);
- if(ortn == noErr) {
- /* dup to a mutable dictionary */
- newDict = CFDictionaryCreateMutableCopy(NULL, 0, existDict);
- }
- else {
- if(certRef == NULL) {
- /* no existing entry, nothing to delete, we're done */
- return 0;
- }
- newDict = CFDictionaryCreateMutable(NULL, 0,
- &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- }
- if(newDict == NULL) {
- ourRtn = ENOMEM;
- goto errOut;
- }
-
- /* issuer / serial number ==> that dictionary */
- keyStr = CFStringCreateWithCString(NULL, principal, kCFStringEncodingASCII);
- if(certRef == NULL) {
- CFDictionaryRemoveValue(newDict, keyStr);
- }
- else {
- cfIssuerSerial = CFDataCreate(NULL, issuerSerial.Data, issuerSerial.Length);
- CFDictionarySetValue(newDict, keyStr, cfIssuerSerial);
- }
-
- /* dictionary ==> prefs */
- CFPreferencesSetValue(CFSTR(kPkinitClientCertKey), newDict,
- CFSTR(kPkinitClientCertApp), kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
- if(CFPreferencesSynchronize(CFSTR(kPkinitClientCertApp), kCFPreferencesCurrentUser,
- kCFPreferencesAnyHost)) {
- ourRtn = 0;
- }
- else {
- ourRtn = EACCES; /* any better ideas? */
- }
-errOut:
- if(cfIssuerSerial) {
- CFRelease(cfIssuerSerial);
- }
- if(issuerSerial.Data) {
- free(issuerSerial.Data);
- }
- if(existDict) {
- CFRelease(existDict);
- }
- if(newDict) {
- CFRelease(newDict);
- }
- if(keyStr) {
- CFRelease(keyStr);
- }
- return ourRtn;
-}
-
-/*
- * Obtain a reference to the client's cert database. Specify either principal
- * name or client_cert as obtained from krb5_pkinit_get_client_cert().
- */
-krb5_error_code krb5_pkinit_get_client_cert_db(
- const char *principal, /* full principal string */
- krb5_pkinit_signing_cert_t client_cert, /* optional, from krb5_pkinit_get_client_cert() */
- krb5_pkinit_cert_db_t *client_cert_db)/* RETURNED */
-{
- krb5_error_code krtn;
- krb5_pkinit_signing_cert_t local_cert;
-
- assert((client_cert != NULL) || (principal != NULL));
- if(client_cert == NULL) {
- /* caller didn't provide, look it up */
- krtn = krb5_pkinit_get_client_cert(principal, &local_cert);
- if(krtn) {
- return krtn;
- }
- }
- else {
- /* easy case */
- local_cert = client_cert;
- }
- krtn = pkinit_cert_to_db(local_cert, client_cert_db);
- if(client_cert == NULL) {
- krb5_pkinit_release_cert(local_cert);
- }
- return krtn;
-}
-
-#pragma mark --- Public server side functions ---
-
-/*
- * Obtain the KDC signing cert, with optional CA and specific cert specifiers.
- * CAs and cert specifiers are in the form of DER-encoded issuerAndSerialNumbers.
- *
- * The client_spec argument is typically provided by the client as kdcPkId.
- */
-krb5_error_code krb5_pkinit_get_kdc_cert(
- krb5_ui_4 num_trusted_CAs, /* sizeof *trusted_CAs */
- krb5_data *trusted_CAs, /* optional */
- krb5_data *client_spec, /* optional */
- krb5_pkinit_signing_cert_t *kdc_cert)
-{
- SecIdentityRef idRef = NULL;
- OSStatus ortn;
- krb5_error_code ourRtn = 0;
-
- /* OS X: trusted_CAs and client_spec ignored */
-
- ortn = SecIdentityCopySystemIdentity(kSecIdentityDomainKerberosKDC,
- &idRef, NULL);
- if(ortn) {
- pkiCssmErr("SecIdentityCopySystemIdentity", ortn);
- return KRB5_PRINC_NOMATCH;
- }
- *kdc_cert = (krb5_pkinit_signing_cert_t)idRef;
- return ourRtn;
-}
-
-/*
- * Obtain a reference to the KDC's cert database.
- */
-krb5_error_code krb5_pkinit_get_kdc_cert_db(
- krb5_pkinit_cert_db_t *kdc_cert_db)
-{
- krb5_pkinit_signing_cert_t kdcCert = NULL;
- krb5_error_code krtn;
-
- krtn = krb5_pkinit_get_kdc_cert(0, NULL, NULL, &kdcCert);
- if(krtn) {
- return krtn;
- }
- krtn = pkinit_cert_to_db(kdcCert, kdc_cert_db);
- krb5_pkinit_release_cert(kdcCert);
- return krtn;
-}
-
-/*
- * Release certificate references obtained via krb5_pkinit_get_client_cert() and
- * krb5_pkinit_get_kdc_cert().
- */
-void krb5_pkinit_release_cert(
- krb5_pkinit_signing_cert_t cert)
-{
- if(cert == NULL) {
- return;
- }
- CFRelease((CFTypeRef)cert);
-}
-
-/*
- * Release database references obtained via krb5_pkinit_get_client_cert_db() and
- * krb5_pkinit_get_kdc_cert_db().
- */
-extern void krb5_pkinit_release_cert_db(
- krb5_pkinit_cert_db_t cert_db)
-{
- if(cert_db == NULL) {
- return;
- }
- CFRelease((CFTypeRef)cert_db);
-}
-
-
-/*
- * Obtain a mallocd C-string representation of a certificate's SHA1 digest.
- * Only error is a NULL return indicating memory failure.
- * Caller must free the returned string.
- */
-char *krb5_pkinit_cert_hash_str(
- const krb5_data *cert)
-{
- CC_SHA1_CTX ctx;
- char *outstr;
- char *cpOut;
- unsigned char digest[CC_SHA1_DIGEST_LENGTH];
- unsigned dex;
-
- assert(cert != NULL);
- CC_SHA1_Init(&ctx);
- CC_SHA1_Update(&ctx, cert->data, cert->length);
- CC_SHA1_Final(digest, &ctx);
-
- outstr = (char *)malloc((2 * CC_SHA1_DIGEST_LENGTH) + 1);
- if(outstr == NULL) {
- return NULL;
- }
- cpOut = outstr;
- for(dex=0; dex<CC_SHA1_DIGEST_LENGTH; dex++) {
- snprintf(cpOut, 3, "%02X", (unsigned)(digest[dex]));
- cpOut += 2;
- }
- *cpOut = '\0';
- return outstr;
-}
-
-/*
- * Obtain a client's optional list of trusted KDC CA certs (trustedCertifiers)
- * and/or trusted KDC cert (kdcPkId) for a given client and server.
- * All returned values are mallocd and must be freed by caller; the contents
- * of the krb5_datas are DER-encoded certificates.
- */
-krb5_error_code krb5_pkinit_get_server_certs(
- const char *client_principal,
- const char *server_principal,
- krb5_data **trusted_CAs, /* RETURNED, though return value may be NULL */
- krb5_ui_4 *num_trusted_CAs, /* RETURNED */
- krb5_data *kdc_cert) /* RETURNED, though may be 0/NULL */
-{
- /* nothing for now */
- *trusted_CAs = NULL;
- *num_trusted_CAs = 0;
- kdc_cert->data = NULL;
- kdc_cert->length = 0;
- return 0;
-}
-
-#endif /* APPLE_PKINIT */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_apple_client.c - Client side routines for PKINIT, Mac OS X version
- *
- * Created 20 May 2004 by Doug Mitchell at Apple.
- */
-
-#if APPLE_PKINIT
-
-#include "pkinit_client.h"
-#include "pkinit_asn1.h"
-#include "pkinit_apple_utils.h"
-#include "pkinit_cms.h"
-#include <assert.h>
-#include <sys/errno.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-/*
- * Create a PA-PK-AS-REQ message.
- */
-krb5_error_code krb5int_pkinit_as_req_create(
- krb5_context context,
- krb5_timestamp kctime,
- krb5_int32 cusec, /* microseconds */
- krb5_ui_4 nonce,
- const krb5_checksum *cksum,
- krb5_pkinit_signing_cert_t client_cert, /* required */
- const krb5_data *trusted_CAs, /* optional list of CA certs */
- krb5_ui_4 num_trusted_CAs,
- const krb5_data *kdc_cert, /* optional KDC cert */
- krb5_data *as_req) /* mallocd and RETURNED */
-{
- krb5_data auth_pack = {0};
- krb5_error_code krtn;
- krb5_data content_info = {0};
- krb5int_algorithm_id *cms_types = NULL;
- krb5_ui_4 num_cms_types = 0;
-
- /* issuer/serial numbers for trusted_CAs and kdc_cert, if we have them */
- krb5_data *ca_issuer_sn = NULL; /* issuer/serial_num for trusted_CAs */
- krb5_data kdc_issuer_sn = {0}; /* issuer/serial_num for kdc_cert */
- krb5_data *kdc_issuer_sn_p = NULL;
-
- /* optional platform-dependent CMS algorithm preference */
- krtn = krb5int_pkinit_get_cms_types(&cms_types, &num_cms_types);
- if(krtn) {
- return krtn;
- }
-
- /* encode the core authPack */
- krtn = krb5int_pkinit_auth_pack_encode(kctime, cusec, nonce, cksum,
- cms_types, num_cms_types,
- &auth_pack);
- if(krtn) {
- goto errOut;
- }
-
- /* package the AuthPack up in a SignedData inside a ContentInfo */
- krtn = krb5int_pkinit_create_cms_msg(&auth_pack,
- client_cert,
- NULL, /* recip_cert */
- ECT_PkAuthData,
- 0, NULL, /* cms_types */
- &content_info);
- if(krtn) {
- goto errOut;
- }
-
- /* if we have trusted_CAs, get issuer/serials */
- if(trusted_CAs) {
- unsigned dex;
- ca_issuer_sn = (krb5_data *)malloc(num_trusted_CAs * sizeof(krb5_data));
- if(ca_issuer_sn == NULL) {
- krtn = ENOMEM;
- goto errOut;
- }
- for(dex=0; dex<num_trusted_CAs; dex++) {
- krtn = krb5int_pkinit_get_issuer_serial(&trusted_CAs[dex],
- &ca_issuer_sn[dex]);
- if(krtn) {
- goto errOut;
- }
- }
- }
-
- /* If we have a KDC cert, get its issuer/serial */
- if(kdc_cert) {
- krtn = krb5int_pkinit_get_issuer_serial(kdc_cert, &kdc_issuer_sn);
- if(krtn) {
- goto errOut;
- }
- kdc_issuer_sn_p = &kdc_issuer_sn;
- }
-
- /* cook up PA-PK-AS-REQ */
- krtn = krb5int_pkinit_pa_pk_as_req_encode(&content_info,
- ca_issuer_sn, num_trusted_CAs,
- kdc_issuer_sn_p,
- as_req);
-
-errOut:
- if(cms_types) {
- krb5int_pkinit_free_cms_types(cms_types, num_cms_types);
- }
- if(auth_pack.data) {
- free(auth_pack.data);
- }
- if(content_info.data) {
- free(content_info.data);
- }
- if(trusted_CAs) {
- unsigned dex;
- for(dex=0; dex<num_trusted_CAs; dex++) {
- free(ca_issuer_sn[dex].data);
- }
- free(ca_issuer_sn);
- }
- if(kdc_cert) {
- free(kdc_issuer_sn.data);
- }
- return krtn;
-}
-
-/*
- * Parse PA-PK-AS-REP message. Optionally evaluates the message's certificate chain.
- * Optionally returns various components.
- */
-krb5_error_code krb5int_pkinit_as_rep_parse(
- krb5_context context,
- const krb5_data *as_rep,
- krb5_pkinit_signing_cert_t client_cert, /* required */
- krb5_keyblock *key_block, /* RETURNED */
- krb5_checksum *checksum, /* checksum of corresponding AS-REQ */
- /* contents mallocd and RETURNED */
- krb5int_cert_sig_status *cert_status, /* RETURNED */
-
- /*
- * Cert fields, all optionally RETURNED.
- *
- * signer_cert is the full X.509 leaf cert from the incoming SignedData.
- * all_certs is an array of all of the certs in the incoming SignedData,
- * in full X.509 form.
- */
- krb5_data *signer_cert, /* content mallocd */
- unsigned *num_all_certs, /* sizeof *all_certs */
- krb5_data **all_certs) /* krb5_data's and their content mallocd */
-{
- krb5_data reply_key_pack = {0, 0, NULL};
- krb5_error_code krtn;
- krb5_data enc_key_pack = {0, 0, NULL};
- krb5_data dh_signed_data = {0, 0, NULL};
- krb5int_cms_content_type content_type;
- krb5_pkinit_cert_db_t cert_db = NULL;
- krb5_boolean is_signed;
- krb5_boolean is_encrypted;
-
- assert((as_rep != NULL) && (checksum != NULL) &&
- (key_block != NULL) && (cert_status != NULL));
-
- /*
- * Decode the top-level PA-PK-AS-REP
- */
- krtn = krb5int_pkinit_pa_pk_as_rep_decode(as_rep, &dh_signed_data, &enc_key_pack);
- if(krtn) {
- pkiCssmErr("krb5int_pkinit_pa_pk_as_rep_decode", krtn);
- return krtn;
- }
- if(dh_signed_data.data) {
- /* not for this implementation... */
- pkiDebug("krb5int_pkinit_as_rep_parse: unexpected dh_signed_data\n");
- krtn = ASN1_BAD_FORMAT;
- goto err_out;
- }
- if(enc_key_pack.data == NULL) {
- /* REQUIRED for this implementation... */
- pkiDebug("krb5int_pkinit_as_rep_parse: no enc_key_pack\n");
- krtn = ASN1_BAD_FORMAT;
- goto err_out;
- }
-
- krtn = krb5_pkinit_get_client_cert_db(NULL, client_cert, &cert_db);
- if(krtn) {
- pkiDebug("krb5int_pkinit_as_rep_parse: error in krb5_pkinit_get_client_cert_db\n");
- goto err_out;
- }
-
- /*
- * enc_key_pack is an EnvelopedData(SignedData(keyPack), encrypted
- * with our cert (which krb5int_pkinit_parse_content_info() finds
- * implicitly).
- */
- krtn = krb5int_pkinit_parse_cms_msg(&enc_key_pack, cert_db, FALSE,
- &is_signed, &is_encrypted,
- &reply_key_pack, &content_type,
- signer_cert, cert_status, num_all_certs, all_certs);
- if(krtn) {
- pkiDebug("krb5int_pkinit_as_rep_parse: error decoding EnvelopedData\n");
- goto err_out;
- }
- if(!is_encrypted || !is_signed) {
- pkiDebug("krb5int_pkinit_as_rep_parse: not signed and encrypted!\n");
- krtn = KRB5_PARSE_MALFORMED;
- goto err_out;
- }
- if(content_type != ECT_PkReplyKeyKata) {
- pkiDebug("replyKeyPack eContentType %d!\n", (int)content_type);
- krtn = KRB5_PARSE_MALFORMED;
- goto err_out;
- }
-
- /*
- * Finally, decode that inner content as the ReplyKeyPack which contains
- * the actual key and nonce
- */
- krtn = krb5int_pkinit_reply_key_pack_decode(&reply_key_pack, key_block, checksum);
- if(krtn) {
- pkiDebug("krb5int_pkinit_as_rep_parse: error decoding ReplyKeyPack\n");
- }
-
-err_out:
- /* free temp mallocd data that we didn't pass back to caller */
- if(reply_key_pack.data) {
- free(reply_key_pack.data);
- }
- if(enc_key_pack.data) {
- free(enc_key_pack.data);
- }
- if(dh_signed_data.data) {
- free(dh_signed_data.data);
- }
- if(cert_db) {
- krb5_pkinit_release_cert_db(cert_db);
- }
- return krtn;
-}
-
-#endif /* APPLE_PKINIT */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- * pkinit_apple_cms.c - CMS encode/decode routines, Mac OS X version
- *
- * Created 19 May 2004 by Doug Mitchell at Apple.
- */
-
-#if APPLE_PKINIT
-
-#include "pkinit_cms.h"
-#include "pkinit_asn1.h"
-#include "pkinit_apple_utils.h"
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/CMSEncoder.h>
-#include <Security/CMSDecoder.h>
-#include <Security/Security.h>
-#include <assert.h>
-#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
-#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
-
-/*
- * Custom OIDS to specify as eContentType
- */
-#define OID_PKINIT 0x2B, 6, 1, 5, 2, 3
-#define OID_PKINIT_LEN 6
-
-static const uint8 OID_PKINIT_AUTH_DATA[] = {OID_PKINIT, 1};
-static const uint8 OID_PKINIT_RKEY_DATA[] = {OID_PKINIT, 3};
-
-/* these may go public so keep these symbols private */
-static const CSSM_OID _CSSMOID_PKINIT_AUTH_DATA =
-{OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_AUTH_DATA};
-static const CSSM_OID _CSSMOID_PKINIT_RKEY_DATA =
-{OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_RKEY_DATA};
-
-
-#pragma mark ----- CMS utilities ----
-
-#define CFRELEASE(cf) if(cf) { CFRelease(cf); }
-
-/*
- * Convert platform-specific cert/signature status to krb5int_cert_sig_status.
- */
-static krb5int_cert_sig_status pkiCertSigStatus(
- OSStatus certStatus)
-{
- switch(certStatus) {
- case CSSM_OK:
- return pki_cs_good;
- case CSSMERR_CSP_VERIFY_FAILED:
- return pki_cs_sig_verify_fail;
- case CSSMERR_TP_NOT_TRUSTED:
- return pki_cs_no_root;
- case CSSMERR_TP_INVALID_ANCHOR_CERT:
- return pki_cs_unknown_root;
- case CSSMERR_TP_CERT_EXPIRED:
- return pki_cs_expired;
- case CSSMERR_TP_CERT_NOT_VALID_YET:
- return pki_cs_not_valid_yet;
- case CSSMERR_TP_CERT_REVOKED:
- return pki_cs_revoked;
- case KRB5_KDB_UNAUTH:
- return pki_cs_untrusted;
- case CSSMERR_TP_INVALID_CERTIFICATE:
- return pki_cs_bad_leaf;
- default:
- return pki_cs_other_err;
- }
-}
-
-/*
- * Infer krb5int_cert_sig_status from CMSSignerStatus and a CSSM TO
- * cert veriofy result code (obtained via the certVerifyResultCode argument
- * in CMSDecoderCopySignerStatus()).
- */
-static krb5int_cert_sig_status pkiInferSigStatus(
- CMSSignerStatus cms_status,
- OSStatus tp_status)
-{
- switch(cms_status) {
- case kCMSSignerUnsigned:
- return pki_not_signed;
- case kCMSSignerValid:
- return pki_cs_good;
- case kCMSSignerNeedsDetachedContent:
- return pki_bad_cms;
- case kCMSSignerInvalidSignature:
- return pki_cs_sig_verify_fail;
- case kCMSSignerInvalidCert:
- /* proceed with TP status */
- break;
- default:
- return pki_cs_other_err;
- }
-
- /* signature good, infer end status from TP verify */
- return pkiCertSigStatus(tp_status);
-}
-
-/*
- * Cook up a SecCertificateRef from a krb5_data.
- */
-static OSStatus pkiKrb5DataToSecCert(
- const krb5_data *rawCert,
- SecCertificateRef *secCert) /* RETURNED */
-{
- CSSM_DATA certData;
- OSStatus ortn;
-
- assert((rawCert != NULL) && (secCert != NULL));
-
- certData.Data = (uint8 *)rawCert->data;
- certData.Length = rawCert->length;
- ortn = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3,
- CSSM_CERT_ENCODING_DER, secCert);
- if(ortn) {
- pkiCssmErr("SecCertificateCreateFromData", ortn);
- }
- return ortn;
-}
-
-/*
- * Convert CFArray of SecCertificateRefs to a mallocd array of krb5_datas.
- */
-static krb5_error_code pkiCertArrayToKrb5Data(
- CFArrayRef cf_certs,
- unsigned *num_all_certs,
- krb5_data **all_certs)
-{
- CFIndex num_certs;
- krb5_data *allCerts = NULL;
- krb5_error_code krtn = 0;
- CFIndex dex;
-
- if(cf_certs == NULL) {
- *all_certs = NULL;
- return 0;
- }
- num_certs = CFArrayGetCount(cf_certs);
- *num_all_certs = (unsigned)num_certs;
- if(num_certs == 0) {
- *all_certs = NULL;
- return 0;
- }
- allCerts = (krb5_data *)malloc(sizeof(krb5_data) * num_certs);
- if(allCerts == NULL) {
- return ENOMEM;
- }
- for(dex=0; dex<num_certs; dex++) {
- CSSM_DATA cert_data;
- OSStatus ortn;
- SecCertificateRef sec_cert;
-
- sec_cert = (SecCertificateRef)CFArrayGetValueAtIndex(cf_certs, dex);
- ortn = SecCertificateGetData(sec_cert, &cert_data);
- if(ortn) {
- pkiCssmErr("SecCertificateGetData", ortn);
- krtn = KRB5_PARSE_MALFORMED;
- break;
- }
- krtn = pkiCssmDataToKrb5Data(&cert_data, &allCerts[dex]);
- if(krtn) {
- break;
- }
- }
- if(krtn) {
- if(allCerts) {
- free(allCerts);
- }
- }
- else {
- *all_certs = allCerts;
- }
- return krtn;
-}
-
-#pragma mark ----- Create CMS message -----
-
-/*
- * Create a CMS message: either encrypted (EnvelopedData), signed
- * (SignedData), or both (EnvelopedData(SignedData(content)).
- *
- * The message is signed iff signing_cert is non-NULL.
- * The message is encrypted iff recip_cert is non-NULL.
- *
- * The content_type argument specifies to the eContentType
- * for a SignedData's EncapsulatedContentInfo.
- */
-krb5_error_code krb5int_pkinit_create_cms_msg(
- const krb5_data *content, /* Content */
- krb5_pkinit_signing_cert_t signing_cert, /* optional: signed by this cert */
- const krb5_data *recip_cert, /* optional: encrypted with this cert */
- krb5int_cms_content_type content_type, /* OID for EncapsulatedData */
- krb5_ui_4 num_cms_types, /* optional, unused here */
- const krb5int_algorithm_id *cms_types, /* optional, unused here */
- krb5_data *content_info) /* contents mallocd and RETURNED */
-{
- krb5_error_code krtn;
- OSStatus ortn;
- SecCertificateRef sec_recip = NULL;
- CFDataRef cf_content = NULL;
- const CSSM_OID *eContentOid = NULL;
-
- if((signing_cert == NULL) && (recip_cert == NULL)) {
- /* must have one or the other */
- pkiDebug("krb5int_pkinit_create_cms_msg: no signer or recipient\n");
- return KRB5_CRYPTO_INTERNAL;
- }
-
- /*
- * Optional signer cert. Note signing_cert, if present, is
- * a SecIdentityRef.
- */
- if(recip_cert) {
- if(pkiKrb5DataToSecCert(recip_cert, &sec_recip)) {
- krtn = ASN1_BAD_FORMAT;
- goto errOut;
- }
- }
-
- /* optional eContentType */
- if(signing_cert) {
- switch(content_type) {
- case ECT_PkAuthData:
- eContentOid = &_CSSMOID_PKINIT_AUTH_DATA;
- break;
- case ECT_PkReplyKeyKata:
- eContentOid = &_CSSMOID_PKINIT_RKEY_DATA;
- break;
- case ECT_Data:
- /* the only standard/default case we allow */
- break;
- default:
- /* others: no can do */
- pkiDebug("krb5int_pkinit_create_cms_msg: bad contentType\n");
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
- }
-
- /* GO */
- ortn = CMSEncode((SecIdentityRef)signing_cert, sec_recip,
- eContentOid,
- FALSE, /* detachedContent */
- kCMSAttrNone, /* no signed attributes that I know of */
- content->data, content->length,
- &cf_content);
- if(ortn) {
- pkiCssmErr("CMSEncode", ortn);
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
- krtn = pkiCfDataToKrb5Data(cf_content, content_info);
-errOut:
- CFRELEASE(sec_recip);
- CFRELEASE(cf_content);
- return krtn;
-}
-
-#pragma mark ----- Generalized parse ContentInfo ----
-
-/*
- * Parse a ContentInfo as best we can. All return fields are optional.
- * If signer_cert_status is NULL on entry, NO signature or cert evaluation
- * will be performed.
- */
-krb5_error_code krb5int_pkinit_parse_cms_msg(
- const krb5_data *content_info,
- krb5_pkinit_cert_db_t cert_db, /* may be required for SignedData */
- krb5_boolean is_client_msg, /* TRUE : msg is from client */
- krb5_boolean *is_signed, /* RETURNED */
- krb5_boolean *is_encrypted, /* RETURNED */
- krb5_data *raw_data, /* RETURNED */
- krb5int_cms_content_type *inner_content_type,/* Returned, ContentType of */
- /* EncapsulatedData */
- krb5_data *signer_cert, /* RETURNED */
- krb5int_cert_sig_status *signer_cert_status,/* RETURNED */
- unsigned *num_all_certs, /* size of *all_certs RETURNED */
- krb5_data **all_certs) /* entire cert chain RETURNED */
-{
- SecPolicySearchRef policy_search = NULL;
- SecPolicyRef policy = NULL;
- OSStatus ortn;
- krb5_error_code krtn = 0;
- CMSDecoderRef decoder = NULL;
- size_t num_signers;
- CMSSignerStatus signer_status;
- OSStatus cert_verify_status;
- CFArrayRef cf_all_certs = NULL;
- int msg_is_signed = 0;
-
- if(content_info == NULL) {
- pkiDebug("krb5int_pkinit_parse_cms_msg: no ContentInfo\n");
- return KRB5_CRYPTO_INTERNAL;
- }
-
- ortn = CMSDecoderCreate(&decoder);
- if(ortn) {
- return ENOMEM;
- }
- ortn = CMSDecoderUpdateMessage(decoder, content_info->data, content_info->length);
- if(ortn) {
- /* no verify yet, must be bad message */
- krtn = KRB5_PARSE_MALFORMED;
- goto errOut;
- }
- ortn = CMSDecoderFinalizeMessage(decoder);
- if(ortn) {
- pkiCssmErr("CMSDecoderFinalizeMessage", ortn);
- krtn = KRB5_PARSE_MALFORMED;
- goto errOut;
- }
-
- /* expect zero or one signers */
- ortn = CMSDecoderGetNumSigners(decoder, &num_signers);
- switch(num_signers) {
- case 0:
- msg_is_signed = 0;
- break;
- case 1:
- msg_is_signed = 1;
- break;
- default:
- krtn = KRB5_PARSE_MALFORMED;
- goto errOut;
- }
-
- /*
- * We need a cert verify policy even if we're not actually evaluating
- * the cert due to requirements in libsecurity_smime.
- */
- ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
- is_client_msg ? &CSSMOID_APPLE_TP_PKINIT_CLIENT : &CSSMOID_APPLE_TP_PKINIT_SERVER,
- NULL, &policy_search);
- if(ortn) {
- pkiCssmErr("SecPolicySearchCreate", ortn);
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
- ortn = SecPolicySearchCopyNext(policy_search, &policy);
- if(ortn) {
- pkiCssmErr("SecPolicySearchCopyNext", ortn);
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
-
- /* get some basic status that doesn't need heavyweight evaluation */
- if(msg_is_signed) {
- if(is_signed) {
- *is_signed = TRUE;
- }
- if(inner_content_type) {
- CSSM_OID ec_oid = {0, NULL};
- CFDataRef ec_data = NULL;
-
- krb5int_cms_content_type ctype;
-
- ortn = CMSDecoderCopyEncapsulatedContentType(decoder, &ec_data);
- if(ortn || (ec_data == NULL)) {
- pkiCssmErr("CMSDecoderCopyEncapsulatedContentType", ortn);
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
- ec_oid.Data = (uint8 *)CFDataGetBytePtr(ec_data);
- ec_oid.Length = CFDataGetLength(ec_data);
- if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_Data)) {
- ctype = ECT_Data;
- }
- else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_SignedData)) {
- ctype = ECT_SignedData;
- }
- else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_EnvelopedData)) {
- ctype = ECT_EnvelopedData;
- }
- else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_EncryptedData)) {
- ctype = ECT_EncryptedData;
- }
- else if(pkiCompareCssmData(&ec_oid, &_CSSMOID_PKINIT_AUTH_DATA)) {
- ctype = ECT_PkAuthData;
- }
- else if(pkiCompareCssmData(&ec_oid, &_CSSMOID_PKINIT_RKEY_DATA)) {
- ctype = ECT_PkReplyKeyKata;
- }
- else {
- ctype = ECT_Other;
- }
- *inner_content_type = ctype;
- CFRelease(ec_data);
- }
-
- /*
- * Get SignedData's certs if the caller wants them
- */
- if(all_certs) {
- ortn = CMSDecoderCopyAllCerts(decoder, &cf_all_certs);
- if(ortn) {
- pkiCssmErr("CMSDecoderCopyAllCerts", ortn);
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
- krtn = pkiCertArrayToKrb5Data(cf_all_certs, num_all_certs, all_certs);
- if(krtn) {
- goto errOut;
- }
- }
-
- /* optional signer cert */
- if(signer_cert) {
- SecCertificateRef sec_signer_cert = NULL;
- CSSM_DATA cert_data;
-
- ortn = CMSDecoderCopySignerCert(decoder, 0, &sec_signer_cert);
- if(ortn) {
- /* should never happen if it's signed */
- pkiCssmErr("CMSDecoderCopySignerStatus", ortn);
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
- ortn = SecCertificateGetData(sec_signer_cert, &cert_data);
- if(ortn) {
- pkiCssmErr("SecCertificateGetData", ortn);
- CFRelease(sec_signer_cert);
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
- krtn = pkiDataToKrb5Data(cert_data.Data, cert_data.Length, signer_cert);
- CFRelease(sec_signer_cert);
- if(krtn) {
- goto errOut;
- }
- }
- }
- else {
- /* not signed */
- if(is_signed) {
- *is_signed = FALSE;
- }
- if(inner_content_type) {
- *inner_content_type = ECT_Other;
- }
- if(signer_cert) {
- signer_cert->data = NULL;
- signer_cert->length = 0;
- }
- if(signer_cert_status) {
- *signer_cert_status = pki_not_signed;
- }
- if(num_all_certs) {
- *num_all_certs = 0;
- }
- if(all_certs) {
- *all_certs = NULL;
- }
- }
- if(is_encrypted) {
- Boolean bencr;
- ortn = CMSDecoderIsContentEncrypted(decoder, &bencr);
- if(ortn) {
- pkiCssmErr("CMSDecoderCopySignerStatus", ortn);
- krtn = KRB5_CRYPTO_INTERNAL;
- goto errOut;
- }
- *is_encrypted = bencr ? TRUE : FALSE;
- }
-
- /*
- * Verify signature and cert. The actual verify operation is optional,
- * per our signer_cert_status argument, but we do this anyway if we need
- * to get the signer cert.
- */
- if((signer_cert_status != NULL) || (signer_cert != NULL)) {
-
- ortn = CMSDecoderCopySignerStatus(decoder,
- 0, /* signerIndex */
- policy,
- signer_cert_status ? TRUE : FALSE, /* evaluateSecTrust */
- &signer_status,
- NULL, /* secTrust - not needed */
- &cert_verify_status);
- if(ortn) {
- /* gross error - subsequent processing impossible */
- pkiCssmErr("CMSDecoderCopySignerStatus", ortn);
- krtn = KRB5_PARSE_MALFORMED;
- goto errOut;
- }
- }
- /* obtain & return status */
- if(signer_cert_status) {
- *signer_cert_status = pkiInferSigStatus(signer_status, cert_verify_status);
- }
-
- /* finally, the payload */
- if(raw_data) {
- CFDataRef cf_content = NULL;
-
- ortn = CMSDecoderCopyContent(decoder, &cf_content);
- if(ortn) {
- pkiCssmErr("CMSDecoderCopyContent", ortn);
- krtn = KRB5_PARSE_MALFORMED;
- goto errOut;
- }
- krtn = pkiCfDataToKrb5Data(cf_content, raw_data);
- CFRELEASE(cf_content);
- }
-errOut:
- CFRELEASE(policy_search);
- CFRELEASE(policy);
- CFRELEASE(cf_all_certs);
- CFRELEASE(decoder);
- return krtn;
-}
-
-krb5_error_code krb5int_pkinit_get_cms_types(
- krb5int_algorithm_id **supported_cms_types, /* RETURNED */
- krb5_ui_4 *num_supported_cms_types) /* RETURNED */
-{
- /* no preference */
- *supported_cms_types = NULL;
- *num_supported_cms_types = 0;
- return 0;
-}
-
-krb5_error_code krb5int_pkinit_free_cms_types(
- krb5int_algorithm_id *supported_cms_types,
- krb5_ui_4 num_supported_cms_types)
-{
- /*
- * We don't return anything from krb5int_pkinit_get_cms_types(), and
- * if we did, it would be a pointer to a statically declared array,
- * so this is a nop.
- */
- return 0;
-}
-
-#endif /* APPLE_PKINIT */
+++ /dev/null
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (c) 2004-2008 Apple Inc. All Rights Reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government. It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Apple Inc. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Apple Inc. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- */
-
-/*
- * pkinit_apple_utils.c - PKINIT utilities, Mac OS X version
- *
- * Created 19 May 2004 by Doug Mitchell at Apple.
- */
-
-#if APPLE_PKINIT
-
-#include "pkinit_apple_utils.h"
-#include "pkinit_asn1.h"
-#include <sys/errno.h>
-#include <assert.h>
-#include <string.h>
-#include <time.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <Security/Security.h>
-
-/*
- * Cruft needed to attach to a module
- */
-static CSSM_VERSION vers = {2, 0};
-static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
-
-/*
- * Standard app-level memory functions required by CDSA.
- */
-static void * cuAppMalloc (CSSM_SIZE size, void *allocRef) {
- return( malloc(size) );
-}
-
-static void cuAppFree (void *mem_ptr, void *allocRef) {
- free(mem_ptr);
- return;
-}
-
-static void * cuAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
- return( realloc( ptr, size ) );
-}
-
-static void * cuAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
- return( calloc( num, size ) );
-}
-
-static CSSM_API_MEMORY_FUNCS memFuncs = {
- cuAppMalloc,
- cuAppFree,
- cuAppRealloc,
- cuAppCalloc,
- NULL
-};
-
-/*
- * Init CSSM; returns CSSM_FALSE on error. Reusable.
- */
-static CSSM_BOOL cssmInitd = CSSM_FALSE;
-
-static CSSM_BOOL cuCssmStartup()
-{
- CSSM_RETURN crtn;
- CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
-
- if(cssmInitd) {
- return CSSM_TRUE;
- }
- crtn = CSSM_Init (&vers,
- CSSM_PRIVILEGE_SCOPE_NONE,
- &testGuid,
- CSSM_KEY_HIERARCHY_NONE,
- &pvcPolicy,
- NULL /* reserved */);
- if(crtn != CSSM_OK)
- {
- return CSSM_FALSE;
- }
- else {
- cssmInitd = CSSM_TRUE;
- return CSSM_TRUE;
- }
-}
-
-CSSM_CL_HANDLE pkiClStartup(void)
-{
- CSSM_CL_HANDLE clHand;
- CSSM_RETURN crtn;
-
- if(cuCssmStartup() == CSSM_FALSE) {
- return 0;
- }
- crtn = CSSM_ModuleLoad(&gGuidAppleX509CL,
- CSSM_KEY_HIERARCHY_NONE,
- NULL, /* eventHandler */
- NULL); /* AppNotifyCallbackCtx */
- if(crtn) {
- return 0;
- }
- crtn = CSSM_ModuleAttach (&gGuidAppleX509CL,
- &vers,
- &memFuncs, /* memFuncs */
- 0, /* SubserviceID */
- CSSM_SERVICE_CL, /* SubserviceFlags - Where is this used? */
- 0, /* AttachFlags */
- CSSM_KEY_HIERARCHY_NONE,
- NULL, /* FunctionTable */
- 0, /* NumFuncTable */
- NULL, /* reserved */
- &clHand);
- if(crtn) {
- return 0;
- }
- else {
- return clHand;
- }
-}
-
-CSSM_RETURN pkiClDetachUnload(
- CSSM_CL_HANDLE clHand)
-{
- CSSM_RETURN crtn = CSSM_ModuleDetach(clHand);
- if(crtn) {
- return crtn;
- }
- return CSSM_ModuleUnload(&gGuidAppleX509CL, NULL, NULL);
-}
-
-/*
- * CSSM_DATA <--> krb5_ui_4
- */
-krb5_error_code pkiDataToInt(
- const CSSM_DATA *cdata,
- krb5_int32 *i) /* RETURNED */
-{
- krb5_ui_4 len;
- krb5_int32 rtn = 0;
- krb5_ui_4 dex;
- uint8 *cp = NULL;
-
- if((cdata->Length == 0) || (cdata->Data == NULL)) {
- *i = 0;
- return 0;
- }
- len = cdata->Length;
- if(len > sizeof(krb5_int32)) {
- return ASN1_BAD_LENGTH;
- }
-
- cp = cdata->Data;
- for(dex=0; dex<len; dex++) {
- rtn = (rtn << 8) | *cp++;
- }
- *i = rtn;
- return 0;
-}
-
-krb5_error_code pkiIntToData(
- krb5_int32 num,
- CSSM_DATA *cdata,
- SecAsn1CoderRef coder)
-{
- krb5_ui_4 unum = (krb5_ui_4)num;
- uint32 len = 0;
- uint8 *cp = NULL;
- unsigned i;
-
- if(unum < 0x100) {
- len = 1;
- }
- else if(unum < 0x10000) {
- len = 2;
- }
- else if(unum < 0x1000000) {
- len = 3;
- }
- else {
- len = 4;
- }
- if(SecAsn1AllocItem(coder, cdata, len)) {
- return ENOMEM;
- }
- cp = &cdata->Data[len - 1];
- for(i=0; i<len; i++) {
- *cp-- = unum & 0xff;
- unum >>= 8;
- }
- return 0;
-}
-
-/*
- * raw data --> krb5_data
- */
-krb5_error_code pkiDataToKrb5Data(
- const void *data,
- unsigned dataLen,
- krb5_data *kd)
-{
- assert(data != NULL);
- assert(kd != NULL);
- kd->data = (char *)malloc(dataLen);
- if(kd->data == NULL) {
- return ENOMEM;
- }
- kd->length = dataLen;
- memmove(kd->data, data, dataLen);
- return 0;
-}
-
-/*
- * CSSM_DATA <--> krb5_data
- *
- * CSSM_DATA data is managed by a SecAsn1CoderRef; krb5_data data is mallocd.
- *
- * Both return nonzero on error.
- */
-krb5_error_code pkiCssmDataToKrb5Data(
- const CSSM_DATA *cd,
- krb5_data *kd)
-{
- assert(cd != NULL);
- return pkiDataToKrb5Data(cd->Data, cd->Length, kd);
-}
-
-krb5_error_code pkiKrb5DataToCssm(
- const krb5_data *kd,
- CSSM_DATA *cd,
- SecAsn1CoderRef coder)
-{
- assert((cd != NULL) && (kd != NULL));
- if(SecAsn1AllocCopy(coder, kd->data, kd->length, cd)) {
- return ENOMEM;
- }
- return 0;
-}
-
-/*
- * CFDataRef --> krb5_data, mallocing the destination contents.
- */
-krb5_error_code pkiCfDataToKrb5Data(
- CFDataRef cfData,
- krb5_data *kd) /* content mallocd and RETURNED */
-{
- return pkiDataToKrb5Data(CFDataGetBytePtr(cfData),
- CFDataGetLength(cfData), kd);
-}
-
-krb5_boolean pkiCompareCssmData(
- const CSSM_DATA *d1,
- const CSSM_DATA *d2)
-{
- if((d1 == NULL) || (d2 == NULL)) {
- return FALSE;
- }
- if(d1->Length != d2->Length) {
- return FALSE;
- }
- if(memcmp(d1->Data, d2->Data, d1->Length)) {
- return FALSE;
- }
- else {
- return TRUE;
- }
-}
-
-/*
- * krb5_timestamp --> a mallocd string in generalized format
- */
-krb5_error_code pkiKrbTimestampToStr(
- krb5_timestamp kts,
- char **str) /* mallocd and RETURNED */
-{
- char *outStr = NULL;
- time_t gmt_time = kts;
- struct tm *utc = gmtime(&gmt_time);
- if (utc == NULL ||
- utc->tm_year > 8099 || utc->tm_mon > 11 ||
- utc->tm_mday > 31 || utc->tm_hour > 23 ||
- utc->tm_min > 59 || utc->tm_sec > 59) {
- return ASN1_BAD_GMTIME;
- }
- if (asprintf(&outStr, "%04d%02d%02d%02d%02d%02dZ",
- utc->tm_year + 1900, utc->tm_mon + 1,
- utc->tm_mday, utc->tm_hour, utc->tm_min, utc->tm_sec) < 0) {
- return ENOMEM;
- }
- *str = outStr;
- return 0;
-}
-
-krb5_error_code pkiTimeStrToKrbTimestamp(
- const char *str,
- unsigned len,
- krb5_timestamp *kts) /* RETURNED */
-{
- char szTemp[5];
- unsigned x;
- unsigned i;
- char *cp;
- struct tm tmp;
- time_t t;
-
- if(len != 15) {
- return ASN1_BAD_LENGTH;
- }
-
- if((str == NULL) || (kts == NULL)) {
- return KRB5_CRYPTO_INTERNAL;
- }
-
- cp = (char *)str;
- memset(&tmp, 0, sizeof(tmp));
-
- /* check that all characters except last are digits */
- for(i=0; i<(len - 1); i++) {
- if ( !(isdigit(cp[i])) ) {
- return ASN1_BAD_TIMEFORMAT;
- }
- }
-
- /* check last character is a 'Z' */
- if(cp[len - 1] != 'Z' ) {
- return ASN1_BAD_TIMEFORMAT;
- }
-
- /* YEAR */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = *cp++;
- szTemp[3] = *cp++;
- szTemp[4] = '\0';
- x = atoi( szTemp );
- /* by definition - tm_year is year - 1900 */
- tmp.tm_year = x - 1900;
-
- /* MONTH */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- /* in the string, months are from 1 to 12 */
- if((x > 12) || (x <= 0)) {
- return ASN1_BAD_TIMEFORMAT;
- }
- /* in a tm, 0 to 11 */
- tmp.tm_mon = x - 1;
-
- /* DAY */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- /* 1..31 */
- if((x > 31) || (x <= 0)) {
- return ASN1_BAD_TIMEFORMAT;
- }
- tmp.tm_mday = x;
-
- /* HOUR */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- if((x > 23) || (x < 0)) {
- return ASN1_BAD_TIMEFORMAT;
- }
- tmp.tm_hour = x;
-
- /* MINUTE */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- if((x > 59) || (x < 0)) {
- return ASN1_BAD_TIMEFORMAT;
- }
- tmp.tm_min = x;
-
- /* SECOND */
- szTemp[0] = *cp++;
- szTemp[1] = *cp++;
- szTemp[2] = '\0';
- x = atoi( szTemp );
- if((x > 59) || (x < 0)) {
- return ASN1_BAD_TIMEFORMAT;
- }
- tmp.tm_sec = x;
- t = timegm(&tmp);
- if(t == -1) {
- return ASN1_BAD_TIMEFORMAT;
- }
- *kts = t;
- return 0;
-}
-
-/*
- * How many items in a NULL-terminated array of pointers?
- */
-unsigned pkiNssArraySize(
- const void **array)
-{
- unsigned count = 0;
- if (array) {
- while (*array++) {
- count++;
- }
- }
- return count;
-}
-
-#endif /* APPLE_PKINIT */
*/
#include "k5-int.h"
-#if APPLE_PKINIT
-#include "pkinit_client.h"
-#include "pkinit_cert_store.h"
-#endif /* APPLE_PKINIT */
#include "osconf.h"
#include <krb5/preauth_plugin.h>
#include "int-proto.h"
return 0;
}
-#if APPLE_PKINIT
-/*
- * PKINIT. One function to generate AS-REQ, one to parse AS-REP
- */
-#define PKINIT_DEBUG 0
-#if PKINIT_DEBUG
-#define kdcPkinitDebug(args...) printf(args)
-#else
-#define kdcPkinitDebug(args...)
-#endif
-
-static krb5_error_code
-pa_pkinit_gen_req(krb5_context context,
- krb5_kdc_req *request,
- krb5_pa_data *in_padata,
- krb5_pa_data **out_padata,
- krb5_data *salt,
- krb5_data *s2kparams,
- krb5_enctype *etype,
- krb5_keyblock *as_key,
- krb5_prompter_fct prompter,
- void *prompter_data,
- krb5_gic_get_as_key_fct gak_fct,
- void *gak_data)
-{
- krb5_error_code krtn;
- krb5_data out_data = {0, 0, NULL};
- krb5_timestamp kctime = 0;
- krb5_int32 cusec = 0;
- krb5_ui_4 nonce = 0;
- krb5_checksum cksum;
- krb5_pkinit_signing_cert_t client_cert;
- krb5_data *der_req = NULL;
- char *client_principal = NULL;
- char *server_principal = NULL;
- unsigned char nonce_bytes[4];
- krb5_data nonce_data = {0, 4, (char *)nonce_bytes};
- int dex;
-
- /*
- * Trusted CA list and specific KC cert optionally obtained via
- * krb5_pkinit_get_server_certs(). All are DER-encoded certs.
- */
- krb5_data *trusted_CAs = NULL;
- krb5_ui_4 num_trusted_CAs;
- krb5_data kdc_cert = {0};
-
- kdcPkinitDebug("pa_pkinit_gen_req\n");
-
- /* If we don't have a client cert, we're done */
- if(request->client == NULL) {
- kdcPkinitDebug("No request->client; aborting PKINIT\n");
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
- krtn = krb5_unparse_name(context, request->client, &client_principal);
- if(krtn) {
- return krtn;
- }
- krtn = krb5_pkinit_get_client_cert(client_principal, &client_cert);
- free(client_principal);
- if(krtn) {
- kdcPkinitDebug("No client cert; aborting PKINIT\n");
- return krtn;
- }
-
- /* optional platform-dependent CA list and KDC cert */
- krtn = krb5_unparse_name(context, request->server, &server_principal);
- if(krtn) {
- goto cleanup;
- }
- krtn = krb5_pkinit_get_server_certs(client_principal, server_principal,
- &trusted_CAs, &num_trusted_CAs, &kdc_cert);
- if(krtn) {
- goto cleanup;
- }
-
- /* checksum of the encoded KDC-REQ-BODY */
- krtn = encode_krb5_kdc_req_body(request, &der_req);
- if(krtn) {
- kdcPkinitDebug("encode_krb5_kdc_req_body returned %d\n", (int)krtn);
- goto cleanup;
- }
- krtn = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0, der_req, &cksum);
- if(krtn) {
- goto cleanup;
- }
-
- krtn = krb5_us_timeofday(context, &kctime, &cusec);
- if(krtn) {
- goto cleanup;
- }
-
- /* cook up a random 4-byte nonce */
- krtn = krb5_c_random_make_octets(context, &nonce_data);
- if(krtn) {
- goto cleanup;
- }
- for(dex=0; dex<4; dex++) {
- nonce <<= 8;
- nonce |= nonce_bytes[dex];
- }
-
- krtn = krb5int_pkinit_as_req_create(context,
- kctime, cusec, nonce, &cksum,
- client_cert,
- trusted_CAs, num_trusted_CAs,
- (kdc_cert.data ? &kdc_cert : NULL),
- &out_data);
- if(krtn) {
- kdcPkinitDebug("error %d on pkinit_as_req_create; aborting PKINIT\n", (int)krtn);
- goto cleanup;
- }
- *out_padata = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
- if(*out_padata == NULL) {
- krtn = ENOMEM;
- free(out_data.data);
- goto cleanup;
- }
- (*out_padata)->magic = KV5M_PA_DATA;
- (*out_padata)->pa_type = KRB5_PADATA_PK_AS_REQ;
- (*out_padata)->length = out_data.length;
- (*out_padata)->contents = (krb5_octet *)out_data.data;
- krtn = 0;
-cleanup:
- if(client_cert) {
- krb5_pkinit_release_cert(client_cert);
- }
- if(cksum.contents) {
- free(cksum.contents);
- }
- if (der_req) {
- krb5_free_data(context, der_req);
- }
- if(server_principal) {
- free(server_principal);
- }
- /* free data mallocd by krb5_pkinit_get_server_certs() */
- if(trusted_CAs) {
- unsigned udex;
- for(udex=0; udex<num_trusted_CAs; udex++) {
- free(trusted_CAs[udex].data);
- }
- free(trusted_CAs);
- }
- if(kdc_cert.data) {
- free(kdc_cert.data);
- }
- return krtn;
-
-}
-
-/* If and only if the realm is that of a Local KDC, accept
- * the KDC certificate as valid if its hash matches the
- * realm.
- */
-static krb5_boolean
-local_kdc_cert_match(krb5_context context,
- krb5_data *signer_cert,
- krb5_principal client)
-{
- static const char lkdcprefix[] = "LKDC:SHA1.";
- krb5_boolean match = FALSE;
- size_t cert_hash_len;
- char *cert_hash;
- const char *realm_hash;
- size_t realm_hash_len;
-
- if (client->realm.length <= sizeof(lkdcprefix) ||
- 0 != memcmp(lkdcprefix, client->realm.data, sizeof(lkdcprefix)-1))
- return match;
- realm_hash = &client->realm.data[sizeof(lkdcprefix)-1];
- realm_hash_len = client->realm.length - sizeof(lkdcprefix) + 1;
- kdcPkinitDebug("checking realm versus certificate hash\n");
- if (NULL != (cert_hash = krb5_pkinit_cert_hash_str(signer_cert))) {
- kdcPkinitDebug("hash = %s\n", cert_hash);
- cert_hash_len = strlen(cert_hash);
- if (cert_hash_len == realm_hash_len &&
- 0 == memcmp(cert_hash, realm_hash, cert_hash_len))
- match = TRUE;
- free(cert_hash);
- }
- kdcPkinitDebug("result: %s\n", match ? "matches" : "does not match");
- return match;
-}
-
-static krb5_error_code
-pa_pkinit_parse_rep(krb5_context context,
- krb5_kdc_req *request,
- krb5_pa_data *in_padata,
- krb5_pa_data **out_padata,
- krb5_data *salt,
- krb5_data *s2kparams,
- krb5_enctype *etype,
- krb5_keyblock *as_key,
- krb5_prompter_fct prompter,
- void *prompter_data,
- krb5_gic_get_as_key_fct gak_fct,
- void *gak_data)
-{
- krb5int_cert_sig_status sig_status = (krb5int_cert_sig_status)-999;
- krb5_error_code krtn;
- krb5_data asRep;
- krb5_keyblock local_key = {0};
- krb5_pkinit_signing_cert_t client_cert;
- char *princ_name = NULL;
- krb5_checksum as_req_checksum_rcd = {0}; /* received checksum */
- krb5_checksum as_req_checksum_gen = {0}; /* calculated checksum */
- krb5_data *encoded_as_req = NULL;
- krb5_data signer_cert = {0};
-
- *out_padata = NULL;
- kdcPkinitDebug("pa_pkinit_parse_rep\n");
- if((in_padata == NULL) || (in_padata->length== 0)) {
- kdcPkinitDebug("pa_pkinit_parse_rep: no in_padata\n");
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
-
- /* If we don't have a client cert, we're done */
- if(request->client == NULL) {
- kdcPkinitDebug("No request->client; aborting PKINIT\n");
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
- krtn = krb5_unparse_name(context, request->client, &princ_name);
- if(krtn) {
- return krtn;
- }
- krtn = krb5_pkinit_get_client_cert(princ_name, &client_cert);
- free(princ_name);
- if(krtn) {
- kdcPkinitDebug("No client cert; aborting PKINIT\n");
- return krtn;
- }
-
- memset(&local_key, 0, sizeof(local_key));
- asRep.data = (char *)in_padata->contents;
- asRep.length = in_padata->length;
- krtn = krb5int_pkinit_as_rep_parse(context, &asRep, client_cert,
- &local_key, &as_req_checksum_rcd, &sig_status,
- &signer_cert, NULL, NULL);
- if(krtn) {
- kdcPkinitDebug("pkinit_as_rep_parse returned %d\n", (int)krtn);
- return krtn;
- }
- switch(sig_status) {
- case pki_cs_good:
- break;
- case pki_cs_unknown_root:
- if (local_kdc_cert_match(context, &signer_cert, request->client))
- break;
- /* FALLTHROUGH */
- default:
- kdcPkinitDebug("pa_pkinit_parse_rep: bad cert/sig status %d\n",
- (int)sig_status);
- krtn = KRB5KDC_ERR_PREAUTH_FAILED;
- goto error_out;
- }
-
- /* calculate checksum of incoming AS-REQ using the decryption key
- * we just got from the ReplyKeyPack */
- krtn = encode_krb5_as_req(request, &encoded_as_req);
- if(krtn) {
- goto error_out;
- }
- krtn = krb5_c_make_checksum(context, context->kdc_req_sumtype,
- &local_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
- encoded_as_req, &as_req_checksum_gen);
- if(krtn) {
- goto error_out;
- }
- if((as_req_checksum_gen.length != as_req_checksum_rcd.length) ||
- memcmp(as_req_checksum_gen.contents,
- as_req_checksum_rcd.contents,
- as_req_checksum_gen.length)) {
- kdcPkinitDebug("pa_pkinit_parse_rep: checksum miscompare\n");
- krtn = KRB5KDC_ERR_PREAUTH_FAILED;
- goto error_out;
- }
-
- /* We have the key; transfer to caller */
- if (as_key->length) {
- krb5_free_keyblock_contents(context, as_key);
- }
- *as_key = local_key;
-
-#if PKINIT_DEBUG
- fprintf(stderr, "pa_pkinit_parse_rep: SUCCESS\n");
- fprintf(stderr, "enctype %d keylen %d keydata %02x %02x %02x %02x...\n",
- (int)as_key->enctype, (int)as_key->length,
- as_key->contents[0], as_key->contents[1],
- as_key->contents[2], as_key->contents[3]);
-#endif
-
- krtn = 0;
-
-error_out:
- if (signer_cert.data) {
- free(signer_cert.data);
- }
- if(as_req_checksum_rcd.contents) {
- free(as_req_checksum_rcd.contents);
- }
- if(as_req_checksum_gen.contents) {
- free(as_req_checksum_gen.contents);
- }
- if(encoded_as_req) {
- krb5_free_data(context, encoded_as_req);
- }
- if(krtn && (local_key.contents != NULL)) {
- krb5_free_keyblock_contents(context, &local_key);
- }
- return krtn;
-}
-#endif /* APPLE_PKINIT */
-
/* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
#define SAMDATA(kdata, str, maxsize) \
pa_salt,
PA_INFO,
},
-#if APPLE_PKINIT
- {
- KRB5_PADATA_PK_AS_REQ,
- pa_pkinit_gen_req,
- PA_INFO,
- },
- {
- KRB5_PADATA_PK_AS_REP,
- pa_pkinit_parse_rep,
- PA_REAL,
- },
-#endif /* APPLE_PKINIT */
{
KRB5_PADATA_SAM_CHALLENGE_2,
pa_sam_2,
{ KRB5_KDB_SALTTYPE_ONLYREALM, "onlyrealm", "Version 5 - Realm Only" },
{ KRB5_KDB_SALTTYPE_SPECIAL, "special", "Special" },
{ KRB5_KDB_SALTTYPE_AFS3, "afs3", "AFS version 3" },
-#if PKINIT_APPLE
- { KRB5_KDB_SALTTYPE_CERTHASH, "certhash", "PKINIT Cert Hash" }
-#endif /* PKINIT_APPLE */
};
static const int salttype_table_nents = sizeof(salttype_table)/
sizeof(salttype_table[0]);