提交 2a1ef754 编写于 作者: R Richard Levitte

Patches from Vern Staats <staatsvr@asc.hpc.mil> to get Kerberos 5 in

SSL according to RFC 2712.  His comment is:

This is a patch to openssl-SNAP-20010702 to support Kerberized SSL
authentication.  I'm expecting to have the full kssl-0.5 kit up on
sourceforge by the end of the week.  The full kit includes patches
for mod-ssl, apache, and a few text clients.  The sourceforge URL
is http://sourceforge.net/projects/kssl/ .

Thanks to a note from Simon Wilkinson I've replaced my KRB5 AP_REQ
message with a real KerberosWrapper struct.  I think this is fully
RFC 2712 compliant now, including support for the optional
authenticator field.  I also added openssl-style ASN.1 macros for
a few Kerberos structs; see crypto/krb5/ if you're interested.
上级 c148d709
......@@ -723,6 +723,7 @@ if ($no_krb5
}
else
{
my ($lresolv, $lpath, $lext);
if ($withargs{"krb5-flavor"} =~ /^[Hh]eimdal$/)
{
$withargs{"krb5-dir"} = "/usr/heimdal"
......@@ -732,7 +733,7 @@ else
if $withargs{"krb5-lib"} eq "";
$cflags="-DKRB5_HEIMDAL $cflags";
}
if ($withargs{"krb5-flavor"} =~ /^[Mm][Ii][Tt]$/)
if ($withargs{"krb5-flavor"} =~ /^[Mm][Ii][Tt]/)
{
$withargs{"krb5-dir"} = "/usr/kerberos"
if $withargs{"krb5-dir"} eq "";
......@@ -740,9 +741,27 @@ else
"/lib -lgssapi_krb5 -lkrb5 -lcom_err -lk5crypto"
if $withargs{"krb5-lib"} eq "";
$cflags="-DKRB5_MIT $cflags";
$withargs{"krb5-flavor"} =~ s/^[Mm][Ii][Tt][._-]*//;
if ($withargs{"krb5-flavor"} =~ /^1[._-]*[01]/)
{
$cflags="-DKRB5_MIT_OLD11 $cflags";
}
}
LRESOLV:
foreach $lpath ("/lib", "/usr/lib")
{
foreach $lext ("a", "so")
{
$lresolv = "$lpath/libresolv.$lext";
last LRESOLV if (-r "$lresolv");
$lresolv = "";
}
}
$withargs{"krb5-lib"} .= " -lresolv"
if ("$lresolv");
$withargs{"krb5-include"} = "-I".$withargs{"krb5-dir"}."/include"
if $withargs{"krb5-include"} eq "" && $withargs{"krb5-dir"} ne "";
if $withargs{"krb5-include"} eq "" &&
$withargs{"krb5-dir"} ne "";
}
# The DSO code currently always implements all functions so that no
......
......@@ -168,7 +168,7 @@ SDIRS= \
des rc2 rc4 rc5 idea bf cast \
bn ec rsa dsa dh dso engine rijndael \
buffer bio stack lhash rand err objects \
evp asn1 pem x509 x509v3 conf txt_db pkcs7 pkcs12 comp ocsp ui
evp asn1 pem x509 x509v3 conf txt_db pkcs7 pkcs12 comp ocsp ui krb5
# tests to perform. "alltests" is a special word indicating that all tests
# should be performed.
......@@ -458,7 +458,7 @@ depend:
do \
if [ -d "$$i" ]; then \
(cd $$i && echo "making dependencies $$i..." && \
$(MAKE) SDIRS='${SDIRS}' DEPFLAG='${DEPFLAG}' MAKEDEPPROG='${MAKEDEPPROG}' depend ) || exit 1; \
$(MAKE) SDIRS='${SDIRS}' DEPFLAG='${DEPFLAG}' MAKEDEPPROG='${MAKEDEPPROG}' KRB5_INCLUDES='${KRB5_INCLUDES}' depend ) || exit 1; \
fi; \
done;
......
......@@ -863,8 +863,10 @@ static int sv_body(char *hostname, int s, unsigned char *context)
#ifndef OPENSSL_NO_KRB5
if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
{
kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVICE, KRB5SVC);
kssl_ctx_setstring(con->kssl_ctx, KSSL_KEYTAB, KRB5KEYTAB);
kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVICE,
KRB5SVC);
kssl_ctx_setstring(con->kssl_ctx, KSSL_KEYTAB,
KRB5KEYTAB);
}
#endif /* OPENSSL_NO_KRB5 */
if(context)
......@@ -1249,6 +1251,13 @@ static int www_body(char *hostname, int s, unsigned char *context)
if (!BIO_set_write_buffer_size(io,bufsize)) goto err;
if ((con=SSL_new(ctx)) == NULL) goto err;
#ifndef OPENSSL_NO_KRB5
if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
{
kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVICE, KRB5SVC);
kssl_ctx_setstring(con->kssl_ctx, KSSL_KEYTAB, KRB5KEYTAB);
}
#endif /* OPENSSL_NO_KRB5 */
if(context) SSL_set_session_id_context(con, context,
strlen((char *)context));
......
......@@ -822,6 +822,7 @@ DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT)
DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING)
DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING)
DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING)
DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING)
DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME)
DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME)
DECLARE_ASN1_FUNCTIONS(ASN1_TIME)
......
......@@ -91,6 +91,9 @@ IMPLEMENT_ASN1_FUNCTIONS(ASN1_T61STRING)
IMPLEMENT_ASN1_TYPE(ASN1_IA5STRING)
IMPLEMENT_ASN1_FUNCTIONS(ASN1_IA5STRING)
IMPLEMENT_ASN1_TYPE(ASN1_GENERALSTRING)
IMPLEMENT_ASN1_FUNCTIONS(ASN1_GENERALSTRING)
IMPLEMENT_ASN1_TYPE(ASN1_UTCTIME)
IMPLEMENT_ASN1_FUNCTIONS(ASN1_UTCTIME)
......
#
# OpenSSL/krb5/Makefile.ssl
#
DIR= krb5
TOP= ../..
CC= cc
INCLUDES= -I.. -I$(TOP) -I../../include
CFLAG=-g
INSTALL_PREFIX=
OPENSSLDIR= /usr/local/ssl
INSTALLTOP=/usr/local/ssl
MAKE= make -f Makefile.ssl
MAKEDEPPROG= makedepend
MAKEDEPEND= $(TOP)/util/domd $(TOP) -MD $(MAKEDEPPROG)
MAKEFILE= Makefile.ssl
AR= ar r
CFLAGS= $(INCLUDES) $(CFLAG)
GENERAL=Makefile README
TEST=
APPS=
LIB=$(TOP)/libcrypto.a
LIBSRC= krb5_asn.c
LIBOBJ= krb5_asn.o
SRC= $(LIBSRC)
EXHEADER= krb5_asn.h
HEADER= $(EXHEADER)
ALL= $(GENERAL) $(SRC) $(HEADER)
top:
(cd ../..; $(MAKE) DIRS=crypto SDIRS=$(DIR) sub_all)
all: lib
lib: $(LIBOBJ)
$(AR) $(LIB) $(LIBOBJ)
$(RANLIB) $(LIB)
@touch lib
files:
perl $(TOP)/util/files.pl Makefile.ssl >> $(TOP)/MINFO
links:
$(TOP)/util/point.sh Makefile.ssl Makefile ;
$(PERL) $(TOP)/util/mklink.pl ../../include/openssl $(EXHEADER)
$(PERL) $(TOP)/util/mklink.pl ../../test $(TEST)
$(PERL) $(TOP)/util/mklink.pl ../../apps $(APPS)
install:
@for i in $(EXHEADER) ; \
do \
(cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
done;
tags:
ctags $(SRC)
tests:
lint:
lint -DLINT $(INCLUDES) $(SRC)>fluff
depend:
$(MAKEDEPEND) $(INCLUDES) $(DEPFLAG) $(LIBSRC)
dclean:
$(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
mv -f Makefile.new $(MAKEFILE)
clean:
rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff
# DO NOT DELETE THIS LINE -- make depend depends on it.
krb5_asn.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h
krb5_asn.o: ../../include/openssl/bio.h ../../include/openssl/bn.h
krb5_asn.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
krb5_asn.o: ../../include/openssl/krb5_asn.h
krb5_asn.o: ../../include/openssl/opensslconf.h
krb5_asn.o: ../../include/openssl/opensslv.h ../../include/openssl/safestack.h
krb5_asn.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
krb5_asn.o: krb5_asn.c
/* krb5_asn.c */
/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project,
** using ocsp/{*.h,*asn*.c} as a starting point
*/
/* ====================================================================
* Copyright (c) 2000 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/krb5_asn.h>
ASN1_SEQUENCE(KRB5_ENCDATA) = {
ASN1_EXP(KRB5_ENCDATA, etype, ASN1_INTEGER, 0),
ASN1_EXP_OPT(KRB5_ENCDATA, kvno, ASN1_INTEGER, 1),
ASN1_EXP(KRB5_ENCDATA, cipher, ASN1_OCTET_STRING,2)
} ASN1_SEQUENCE_END(KRB5_ENCDATA)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_ENCDATA)
ASN1_SEQUENCE(KRB5_PRINCNAME) = {
ASN1_EXP(KRB5_PRINCNAME, nametype, ASN1_INTEGER, 0),
ASN1_EXP_SEQUENCE_OF(KRB5_PRINCNAME, namestring, ASN1_GENERALSTRING, 1)
} ASN1_SEQUENCE_END(KRB5_PRINCNAME)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_PRINCNAME)
/* [APPLICATION 1] = 0x61 */
ASN1_SEQUENCE(KRB5_TKTBODY) = {
ASN1_EXP(KRB5_TKTBODY, tktvno, ASN1_INTEGER, 0),
ASN1_EXP(KRB5_TKTBODY, realm, ASN1_GENERALSTRING, 1),
ASN1_EXP(KRB5_TKTBODY, sname, KRB5_PRINCNAME, 2),
ASN1_EXP(KRB5_TKTBODY, encdata, KRB5_ENCDATA, 3)
} ASN1_SEQUENCE_END(KRB5_TKTBODY)
ASN1_ITEM_TEMPLATE(KRB5_TICKET) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_EXPTAG|ASN1_TFLG_APPLICATION, 1,
KRB5_TICKET, KRB5_TKTBODY)
ASN1_ITEM_TEMPLATE_END(KRB5_TICKET)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_TICKET)
/* [APPLICATION 14] = 0x6e */
ASN1_SEQUENCE(KRB5_APREQBODY) = {
ASN1_EXP(KRB5_APREQBODY, pvno, ASN1_INTEGER, 0),
ASN1_EXP(KRB5_APREQBODY, msgtype, ASN1_INTEGER, 1),
ASN1_EXP(KRB5_APREQBODY, apoptions, ASN1_BIT_STRING, 2),
ASN1_EXP(KRB5_APREQBODY, ticket, KRB5_TICKET, 3),
ASN1_EXP(KRB5_APREQBODY, authenticator, KRB5_ENCDATA, 4),
} ASN1_SEQUENCE_END(KRB5_APREQBODY)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_APREQBODY)
ASN1_ITEM_TEMPLATE(KRB5_APREQ) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_EXPTAG|ASN1_TFLG_APPLICATION, 14,
KRB5_APREQ, KRB5_APREQBODY)
ASN1_ITEM_TEMPLATE_END(KRB5_APREQ)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_APREQ)
/* Authenticator stuff */
ASN1_SEQUENCE(KRB5_CHECKSUM) = {
ASN1_EXP(KRB5_CHECKSUM, ctype, ASN1_INTEGER, 0),
ASN1_EXP(KRB5_CHECKSUM, checksum, ASN1_OCTET_STRING,1)
} ASN1_SEQUENCE_END(KRB5_CHECKSUM)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_CHECKSUM)
ASN1_SEQUENCE(KRB5_ENCKEY) = {
ASN1_EXP(KRB5_ENCKEY, ktype, ASN1_INTEGER, 0),
ASN1_EXP(KRB5_ENCKEY, keyvalue, ASN1_OCTET_STRING,1)
} ASN1_SEQUENCE_END(KRB5_ENCKEY)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_ENCKEY)
/* SEQ OF SEQ; see ASN1_EXP_SEQUENCE_OF_OPT() below */
ASN1_SEQUENCE(KRB5_AUTHDATA) = {
ASN1_EXP(KRB5_AUTHDATA, adtype, ASN1_INTEGER, 0),
ASN1_EXP(KRB5_AUTHDATA, addata, ASN1_OCTET_STRING,1)
} ASN1_SEQUENCE_END(KRB5_AUTHDATA)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_AUTHDATA)
/* [APPLICATION 2] = 0x62 */
ASN1_SEQUENCE(KRB5_AUTHENTBODY) = {
ASN1_EXP(KRB5_AUTHENTBODY, avno, ASN1_INTEGER, 0),
ASN1_EXP(KRB5_AUTHENTBODY, crealm, ASN1_GENERALSTRING, 1),
ASN1_EXP(KRB5_AUTHENTBODY, cname, KRB5_PRINCNAME, 2),
ASN1_EXP_OPT(KRB5_AUTHENTBODY, cksum, KRB5_CHECKSUM, 3),
ASN1_EXP(KRB5_AUTHENTBODY, cusec, ASN1_INTEGER, 4),
ASN1_EXP(KRB5_AUTHENTBODY, ctime, ASN1_GENERALIZEDTIME, 5),
ASN1_EXP_OPT(KRB5_AUTHENTBODY, subkey, KRB5_ENCKEY, 6),
ASN1_EXP_OPT(KRB5_AUTHENTBODY, seqnum, ASN1_INTEGER, 7),
ASN1_EXP_SEQUENCE_OF_OPT
(KRB5_AUTHENTBODY, authorization, KRB5_AUTHDATA, 8),
} ASN1_SEQUENCE_END(KRB5_AUTHENTBODY)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_AUTHENTBODY)
ASN1_ITEM_TEMPLATE(KRB5_AUTHENT) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_EXPTAG|ASN1_TFLG_APPLICATION, 2,
KRB5_AUTHENT, KRB5_AUTHENTBODY)
ASN1_ITEM_TEMPLATE_END(KRB5_AUTHENT)
IMPLEMENT_ASN1_FUNCTIONS(KRB5_AUTHENT)
/* krb5_asn.h */
/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project,
** using ocsp/{*.h,*asn*.c} as a starting point
*/
/* ====================================================================
* Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
#ifndef HEADER_KRB5_ASN_H
#define HEADER_KRB5_ASN_H
/*
#include <krb5.h>
*/
#include <openssl/safestack.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ASN.1 from Kerberos RFC 1510
*/
/* EncryptedData ::= SEQUENCE {
** etype[0] INTEGER, -- EncryptionType
** kvno[1] INTEGER OPTIONAL,
** cipher[2] OCTET STRING -- ciphertext
** }
*/
typedef struct krb5_encdata_st
{
ASN1_INTEGER *etype;
ASN1_INTEGER *kvno;
ASN1_OCTET_STRING *cipher;
} KRB5_ENCDATA;
DECLARE_STACK_OF(KRB5_ENCDATA)
/* PrincipalName ::= SEQUENCE {
** name-type[0] INTEGER,
** name-string[1] SEQUENCE OF GeneralString
** }
*/
typedef struct krb5_princname_st
{
ASN1_INTEGER *nametype;
STACK_OF(ASN1_GENERALSTRING) *namestring;
} KRB5_PRINCNAME;
DECLARE_STACK_OF(KRB5_PRINCNAME)
/* Ticket ::= [APPLICATION 1] SEQUENCE {
** tkt-vno[0] INTEGER,
** realm[1] Realm,
** sname[2] PrincipalName,
** enc-part[3] EncryptedData
** }
*/
typedef struct krb5_tktbody_st
{
ASN1_INTEGER *tktvno;
ASN1_GENERALSTRING *realm;
KRB5_PRINCNAME *sname;
KRB5_ENCDATA *encdata;
} KRB5_TKTBODY;
typedef STACK_OF(KRB5_TKTBODY) KRB5_TICKET;
DECLARE_STACK_OF(KRB5_TKTBODY)
/* AP-REQ ::= [APPLICATION 14] SEQUENCE {
** pvno[0] INTEGER,
** msg-type[1] INTEGER,
** ap-options[2] APOptions,
** ticket[3] Ticket,
** authenticator[4] EncryptedData
** }
**
** APOptions ::= BIT STRING {
** reserved(0), use-session-key(1), mutual-required(2) }
*/
typedef struct krb5_ap_req_st
{
ASN1_INTEGER *pvno;
ASN1_INTEGER *msgtype;
ASN1_BIT_STRING *apoptions;
KRB5_TICKET *ticket;
KRB5_ENCDATA *authenticator;
} KRB5_APREQBODY;
typedef STACK_OF(KRB5_APREQBODY) KRB5_APREQ;
DECLARE_STACK_OF(KRB5_APREQBODY)
/* Authenticator Stuff */
/* Checksum ::= SEQUENCE {
** cksumtype[0] INTEGER,
** checksum[1] OCTET STRING
** }
*/
typedef struct krb5_checksum_st
{
ASN1_INTEGER *ctype;
ASN1_OCTET_STRING *checksum;
} KRB5_CHECKSUM;
DECLARE_STACK_OF(KRB5_CHECKSUM)
/* EncryptionKey ::= SEQUENCE {
** keytype[0] INTEGER,
** keyvalue[1] OCTET STRING
** }
*/
typedef struct krb5_encryptionkey_st
{
ASN1_INTEGER *ktype;
ASN1_OCTET_STRING *keyvalue;
} KRB5_ENCKEY;
DECLARE_STACK_OF(KRB5_ENCKEY)
/* AuthorizationData ::= SEQUENCE OF SEQUENCE {
** ad-type[0] INTEGER,
** ad-data[1] OCTET STRING
** }
*/
typedef struct krb5_authorization_st
{
ASN1_INTEGER *adtype;
ASN1_OCTET_STRING *addata;
} KRB5_AUTHDATA;
DECLARE_STACK_OF(KRB5_AUTHDATA);
/* -- Unencrypted authenticator
** Authenticator ::= [APPLICATION 2] SEQUENCE {
** authenticator-vno[0] INTEGER,
** crealm[1] Realm,
** cname[2] PrincipalName,
** cksum[3] Checksum OPTIONAL,
** cusec[4] INTEGER,
** ctime[5] KerberosTime,
** subkey[6] EncryptionKey OPTIONAL,
** seq-number[7] INTEGER OPTIONAL,
** authorization-data[8] AuthorizationData OPTIONAL
** }
*/
typedef struct krb5_authenticator_st
{
ASN1_INTEGER *avno;
ASN1_GENERALSTRING *crealm;
KRB5_PRINCNAME *cname;
KRB5_CHECKSUM *cksum;
ASN1_INTEGER *cusec;
ASN1_GENERALIZEDTIME *ctime;
KRB5_ENCKEY *subkey;
ASN1_INTEGER *seqnum;
KRB5_AUTHDATA *authorization;
} KRB5_AUTHENTBODY;
typedef STACK_OF(KRB5_AUTHENTBODY) KRB5_AUTHENT;
DECLARE_STACK_OF(KRB5_AUTHENTBODY)
/* DECLARE_ASN1_FUNCTIONS(type) = DECLARE_ASN1_FUNCTIONS_name(type, type) =
** type *name##_new(void);
** void name##_free(type *a);
** DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) =
** DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) =
** type *d2i_##name(type **a, unsigned char **in, long len);
** int i2d_##name(type *a, unsigned char **out);
** DECLARE_ASN1_ITEM(itname) = OPENSSL_EXTERN const ASN1_ITEM itname##_it
*/
DECLARE_ASN1_FUNCTIONS(KRB5_ENCDATA)
DECLARE_ASN1_FUNCTIONS(KRB5_PRINCNAME)
DECLARE_ASN1_FUNCTIONS(KRB5_TKTBODY)
DECLARE_ASN1_FUNCTIONS(KRB5_APREQBODY)
DECLARE_ASN1_FUNCTIONS(KRB5_TICKET)
DECLARE_ASN1_FUNCTIONS(KRB5_APREQ)
DECLARE_ASN1_FUNCTIONS(KRB5_CHECKSUM)
DECLARE_ASN1_FUNCTIONS(KRB5_ENCKEY)
DECLARE_ASN1_FUNCTIONS(KRB5_AUTHDATA)
DECLARE_ASN1_FUNCTIONS(KRB5_AUTHENTBODY)
DECLARE_ASN1_FUNCTIONS(KRB5_AUTHENT)
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
*/
#ifdef __cplusplus
}
#endif
#endif
......@@ -56,15 +56,26 @@
*/
/* ssl/kssl.c -- Routines to support (& debug) Kerberos5 auth for openssl
/* ssl/kssl.c -- Routines to support (& debug) Kerberos5 auth for openssl
**
** 19990701 VRS Started.
** 19990701 VRS Started.
** 200011?? Jeffrey Altman, Richard Levitte
** Generalized for Heimdal, Newer MIT, & Win32.
** Integrated into main OpenSSL 0.9.7 snapshots.
** 20010413 Simon Wilkinson, VRS
** Real RFC2712 KerberosWrapper replaces AP_REQ.
*/
#include <openssl/opensslconf.h>
#ifndef OPENSSL_NO_KRB5
#include <string.h>
#define _XOPEN_SOURCE /* glibc2 needs this to declare strptime() */
#include <time.h>
#include <openssl/ssl.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/krb5_asn.h>
/*
* When OpenSSL is built on Windows, we do not want to require that
......@@ -104,6 +115,15 @@
#define krb5_kt_resolve kssl_krb5_kt_resolve
#define krb5_auth_con_init kssl_krb5_auth_con_init
#define krb5_principal_compare kssl_krb5_principal_compare
/* macro #define krb5_kt_get_entry kssl_krb5_kt_get_entry */
#define krb5_decrypt_tkt_part kssl_krb5_decrypt_tkt_part
#define krb5_timeofday kssl_krb5_timeofday
#define krb5_rc_default kssl_krb5_rc_default
#define krb5_krb5_rc_initialize kssl_krb5_rc_initialize
#define krb5_krb5_rc_get_lifespan kssl_krb5_rc_get_lifespan
#define krb5_krb5_rc_destroy kssl_krb5_rc_destroy
/* Prototypes for built in stubs */
void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
void kssl_krb5_free_principal(krb5_context, krb5_principal );
......@@ -117,6 +137,19 @@ krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *,
krb5_const krb5_data *,
krb5_const_principal, krb5_keytab,
krb5_flags *,krb5_ticket **);
krb5_boolean kssl_krb5_principal_compare(krb5_context, krb5_const_principal,
krb5_const_principal);
krb5_error_code krb5_decrypt_tkt_part(krb5_context, krb5_const krb5_keyblock *,
krb5_ticket *);
krb5_error_code krb5_timeofday(krb5_context context, krb5_int32 *timeret);
krb5_error_code krb5_rc_default(krb5_context context, krb5_rcache *rc);
krb5_error_code krb5_rc_initialize(krb5_context context, krb5_rcache rc,
krb5_deltat lifespan);
krb5_error_code krb5_rc_get_lifespan(krb5_context context, krb5_rcache rc,
krb5_deltat *lifespan);
krb5_error_code krb5_rc_destroy(krb5_context context, krb5_rcache rc);
krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
krb5_auth_context *,
krb5_const krb5_flags,
......@@ -144,10 +177,12 @@ krb5_error_code kssl_krb5_cc_get_principal(krb5_context context,
krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
/* Function pointers (almost all Kerberos functions are _stdcall) */
static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)=NULL;
static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )=NULL;
static krb5_error_code(_stdcall *p_krb5_kt_resolve)(krb5_context, krb5_const char *,
krb5_keytab *)=NULL;
static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)
=NULL;
static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )
=NULL;
static krb5_error_code(_stdcall *p_krb5_kt_resolve)
(krb5_context, krb5_const char *, krb5_keytab *)=NULL;
static krb5_error_code (_stdcall *p_krb5_kt_default)(krb5_context,
krb5_keytab *)=NULL;
static krb5_error_code (_stdcall *p_krb5_free_ticket)(krb5_context,
......@@ -158,33 +193,27 @@ static krb5_error_code (_stdcall *p_krb5_rd_req)(krb5_context,
krb5_const_principal,
krb5_keytab, krb5_flags *,
krb5_ticket **)=NULL;
static krb5_error_code (_stdcall *p_krb5_mk_req_extended) (krb5_context,
krb5_auth_context *,
krb5_const krb5_flags,
krb5_data *,
krb5_creds *,
krb5_data * )=NULL;
static krb5_error_code (_stdcall *p_krb5_mk_req_extended)
(krb5_context, krb5_auth_context *,
krb5_const krb5_flags, krb5_data *, krb5_creds *,
krb5_data * )=NULL;
static krb5_error_code (_stdcall *p_krb5_init_context)(krb5_context *)=NULL;
static void (_stdcall *p_krb5_free_context)(krb5_context)=NULL;
static krb5_error_code (_stdcall *p_krb5_cc_default)(krb5_context,
krb5_ccache *)=NULL;
static krb5_error_code (_stdcall *p_krb5_sname_to_principal)(krb5_context,
krb5_const char *,
krb5_const char *,
krb5_int32,
krb5_principal *)=NULL;
static krb5_error_code (_stdcall *p_krb5_get_credentials)(krb5_context,
krb5_const krb5_flags,
krb5_ccache,
krb5_creds *,
krb5_creds * *)=NULL;
static krb5_error_code (_stdcall *p_krb5_auth_con_init)(krb5_context,
krb5_auth_context *)=NULL;
static krb5_error_code (_stdcall *p_krb5_cc_get_principal)(krb5_context context,
krb5_ccache cache,
krb5_principal *principal)=NULL;
static krb5_error_code (_stdcall *p_krb5_auth_con_free)(krb5_context,
krb5_auth_context)=NULL;
static krb5_error_code (_stdcall *p_krb5_sname_to_principal)
(krb5_context, krb5_const char *, krb5_const char *,
krb5_int32, krb5_principal *)=NULL;
static krb5_error_code (_stdcall *p_krb5_get_credentials)
(krb5_context, krb5_const krb5_flags, krb5_ccache,
krb5_creds *, krb5_creds **)=NULL;
static krb5_error_code (_stdcall *p_krb5_auth_con_init)
(krb5_context, krb5_auth_context *)=NULL;
static krb5_error_code (_stdcall *p_krb5_cc_get_principal)
(krb5_context context, krb5_ccache cache,
krb5_principal *principal)=NULL;
static krb5_error_code (_stdcall *p_krb5_auth_con_free)
(krb5_context, krb5_auth_context)=NULL;
static int krb5_loaded = 0; /* only attempt to initialize func ptrs once */
/* Function to Load the Kerberos 5 DLL and initialize function pointers */
......@@ -222,6 +251,20 @@ load_krb5_dll(void)
GetProcAddress( hKRB5_32, "krb5_free_ticket" );
(FARPROC) p_krb5_rd_req =
GetProcAddress( hKRB5_32, "krb5_rd_req" );
(FARPROC) p_krb5_principal_compare =
GetProcAddress( hKRB5_32, "krb5_principal_compare" );
(FARPROC) p_krb5_decrypt_tkt_part =
GetProcAddress( hKRB5_32, "krb5_decrypt_tkt_part" );
(FARPROC) p_krb5_timeofday =
GetProcAddress( hKRB5_32, "krb5_timeofday" );
(FARPROC) p_krb5_rc_default =
GetProcAddress( hKRB5_32, "krb5_rc_default" );
(FARPROC) p_krb5_rc_initialize =
GetProcAddress( hKRB5_32, "krb5_rc_initialize" );
(FARPROC) p_krb5_rc_get_lifespan =
GetProcAddress( hKRB5_32, "krb5_rc_get_lifespan" );
(FARPROC) p_krb5_rc_destroy =
GetProcAddress( hKRB5_32, "krb5_rc_destroy" );
(FARPROC) p_krb5_kt_default =
GetProcAddress( hKRB5_32, "krb5_kt_default" );
(FARPROC) p_krb5_kt_resolve =
......@@ -412,6 +455,92 @@ kssl_krb5_rd_req(krb5_context con, krb5_auth_context * pacon,
return KRB5KRB_ERR_GENERIC;
}
krb5_boolean
krb5_principal_compare(krb5_context con, krb5_const_principal princ1,
krb5_const_principal princ2)
{
if (!krb5_loaded)
load_krb5_dll();
if ( p_krb5_principal_compare )
return(p_krb5_principal_compare(con,princ1,princ2);
else
return KRB5KRB_ERR_GENERIC;
}
krb5_error_code
krb5_decrypt_tkt_part(krb5_context con, krb5_const krb5_keyblock *keys,
krb5_ticket *ticket)
{
if (!krb5_loaded)
load_krb5_dll();
if ( p_krb5_decrypt_tkt_part )
return(p_krb5_decrypt_tkt_part(con,keys,ticket);
else
return KRB5KRB_ERR_GENERIC;
}
krb5_error_code
krb5_timeofday(krb5_context con, krb5_int32 *timeret)
{
if (!krb5_loaded)
load_krb5_dll();
if ( p_krb5_timeofday )
return(p_krb5_timeofday(con,timeret);
else
return KRB5KRB_ERR_GENERIC;
}
krb5_error_code
krb5_rc_default(krb5_context con, krb5_rcache *rc)
{
if (!krb5_loaded)
load_krb5_dll();
if ( p_krb5_rc_default )
return(p_krb5_rc_default(con,rc);
else
return KRB5KRB_ERR_GENERIC;
}
krb5_error_code
krb5_rc_initialize(krb5_context con, krb5_rcache rc, krb5_deltat lifespan)
{
if (!krb5_loaded)
load_krb5_dll();
if ( p_krb5_rc_initialize )
return(p_krb5_rc_initialize(con, rc, lifespan);
else
return KRB5KRB_ERR_GENERIC;
}
krb5_error_code
krb5_rc_get_lifespan(krb5_context con, krb5_rcache rc, krb5_deltat *lifespanp)
{
if (!krb5_loaded)
load_krb5_dll();
if ( p_krb5_rc_get_lifespan )
return(p_krb5_rc_get_lifespan(con, rc, lifespanp);
else
return KRB5KRB_ERR_GENERIC;
}
krb5_error_code
krb5_rc_destroy(krb5_context con, krb5_rcache rc)
{
if (!krb5_loaded)
load_krb5_dll();
if ( p_krb5_rc_destroy )
return(p_krb5_rc_destroy(con, rc);
else
return KRB5KRB_ERR_GENERIC;
}
/* Structure definitions */
#ifndef NO_DEF_KRB5_CCACHE
#ifndef krb5_x
......@@ -432,31 +561,37 @@ typedef struct _krb5_cc_ops
{
krb5_magic magic;
char *prefix;
char * (KRB5_CALLCONV *get_name) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
krb5_error_code (KRB5_CALLCONV *resolve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache *,
const char *));
krb5_error_code (KRB5_CALLCONV *gen_new) KRB5_NPROTOTYPE((krb5_context, krb5_ccache *));
krb5_error_code (KRB5_CALLCONV *init) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_principal));
krb5_error_code (KRB5_CALLCONV *destroy) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
krb5_error_code (KRB5_CALLCONV *close) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
krb5_error_code (KRB5_CALLCONV *store) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_creds *));
krb5_error_code (KRB5_CALLCONV *retrieve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_flags, krb5_creds *,
krb5_creds *));
krb5_error_code (KRB5_CALLCONV *get_princ) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_principal *));
krb5_error_code (KRB5_CALLCONV *get_first) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_cc_cursor *));
krb5_error_code (KRB5_CALLCONV *get_next) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
char * (KRB5_CALLCONV *get_name)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
krb5_error_code (KRB5_CALLCONV *resolve)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache *, const char *));
krb5_error_code (KRB5_CALLCONV *gen_new)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache *));
krb5_error_code (KRB5_CALLCONV *init)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_principal));
krb5_error_code (KRB5_CALLCONV *destroy)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
krb5_error_code (KRB5_CALLCONV *close)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
krb5_error_code (KRB5_CALLCONV *store)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_creds *));
krb5_error_code (KRB5_CALLCONV *retrieve)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_flags, krb5_creds *, krb5_creds *));
krb5_error_code (KRB5_CALLCONV *get_princ)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_principal *));
krb5_error_code (KRB5_CALLCONV *get_first)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_cc_cursor *));
krb5_error_code (KRB5_CALLCONV *get_next)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_cc_cursor *, krb5_creds *));
krb5_error_code (KRB5_CALLCONV *end_get) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_cc_cursor *));
krb5_error_code (KRB5_CALLCONV *remove_cred) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_error_code (KRB5_CALLCONV *end_get)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_cc_cursor *));
krb5_error_code (KRB5_CALLCONV *remove_cred)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_flags, krb5_creds *));
krb5_error_code (KRB5_CALLCONV *set_flags) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
krb5_flags));
krb5_error_code (KRB5_CALLCONV *set_flags)
KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_flags));
} krb5_cc_ops;
#endif /* NO_DEF_KRB5_CCACHE */
......@@ -468,8 +603,10 @@ kssl_krb5_cc_get_principal
if ( p_krb5_cc_get_principal )
return(p_krb5_cc_get_principal(context,cache,principal));
else
return(krb5_x ((cache)->ops->get_princ,(context, cache, principal)));
return(krb5_x
((cache)->ops->get_princ,(context, cache, principal)));
}
#else
#endif /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
char
......@@ -498,6 +635,120 @@ char
}
/* Given KRB5 enctype (basically DES or 3DES), return
*/
EVP_CIPHER *
kssl_map_enc(krb5_enctype enctype)
{
switch (enctype)
{
case ENCTYPE_DES_CBC_CRC:
case ENCTYPE_DES_CBC_MD4:
case ENCTYPE_DES_CBC_MD5:
case ENCTYPE_DES_CBC_RAW:
#if ! defined(KRB5_MIT_OLD11)
case ENCTYPE_DES_HMAC_SHA1:
#endif
return (EVP_CIPHER *) EVP_des_cbc();
break;
case ENCTYPE_DES3_CBC_SHA:
case ENCTYPE_DES3_CBC_RAW:
#if ! defined(KRB5_MIT_OLD11)
case ENCTYPE_DES3_CBC_SHA1:
#endif
return (EVP_CIPHER *) EVP_des_ede3_cbc();
break;
default: return (EVP_CIPHER *) NULL;
break;
}
}
/* Return true:1 if p "looks like" the start of the real authenticator
** described in kssl_skip_confound() below. The ASN.1 pattern is
** "62 xx 30 yy" (APPLICATION-2, SEQUENCE), where xx-yy =~ 2, and
** xx and yy are possibly multi-byte length fields.
*/
int kssl_test_confound(unsigned char *p)
{
int len = 2;
int xx = 0, yy = 0;
if (*p++ != 0x62) return 0;
if (*p > 0x82) return 0;
switch(*p) {
case 0x82: p++; xx = (*p++ << 8); xx += *p++; break;
case 0x81: p++; xx = *p++; break;
case 0x80: return 0;
default: xx = *p++; break;
}
if (*p++ != 0x30) return 0;
if (*p > 0x82) return 0;
switch(*p) {
case 0x82: p++; len+=2; yy = (*p++ << 8); yy += *p++; break;
case 0x81: p++; len++; yy = *p++; break;
case 0x80: return 0;
default: yy = *p++; break;
}
return (xx - len == yy)? 1: 0;
}
/* Allocate, fill, and return cksumlens array of checksum lengths.
** This array holds just the unique elements from the krb5_cksumarray[].
** array[n] == 0 signals end of data.
*/
int *populate_cksumlens(void)
{
int i, j, n = krb5_max_cksum+1;
static int *cklens = NULL;
#ifdef KRB5CHECKAUTH
if (!cklens && !(cklens = (int *) calloc(sizeof(int), n))) return NULL;
for (i=0; i < krb5_max_cksum; i++) {
if (!krb5_cksumarray[i]) continue; /* array has holes */
for (j=0; j < krb5_max_cksum; j++) {
if (cklens[j] == 0) {
cklens[j] = krb5_cksumarray[i]->checksum_length;
break; /* krb5 elem was new: add */
}
if (cklens[j] == krb5_cksumarray[i]->checksum_length) {
break; /* ignore duplicate elements */
}
}
}
#endif /* KRB5CHECKAUTH */
return cklens;
}
/* Return pointer to start of real authenticator within authenticator, or
** return NULL on error.
** Decrypted authenticator looks like this:
** [0 or 8 byte confounder] [4-24 byte checksum] [real authent'r]
** This hackery wouldn't be necessary if MIT KRB5 1.0.6 had the
** krb5_auth_con_getcksumtype() function advertised in its krb5.h.
*/
unsigned char *kssl_skip_confound(krb5_enctype etype, unsigned char *a)
{
int i, cklen, conlen;
static int *cksumlens = NULL;
unsigned char *test_auth;
conlen = (etype)? 8: 0;
if (!cksumlens && !(cksumlens = populate_cksumlens())) return NULL;
for (i=0; (cklen = cksumlens[i]) != 0; i++)
{
test_auth = a + conlen + cklen;
if (kssl_test_confound(test_auth)) return test_auth;
}
return NULL;
}
/* Set kssl_err error info when reason text is a simple string
** kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
*/
......@@ -522,10 +773,10 @@ print_krb5_data(char *label, krb5_data *kdata)
printf("%s[%d] ", label, kdata->length);
for (i=0; i < kdata->length; i++)
{
if (isprint((int) kdata->data[i]))
if (0 && isprint((int) kdata->data[i]))
printf( "%c ", kdata->data[i]);
else
printf( "%02x", kdata->data[i]);
printf( "%02x ", (unsigned char) kdata->data[i]);
}
printf("\n");
}
......@@ -570,7 +821,8 @@ print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
return;
}
#ifdef KRB5_HEIMDAL
printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype, keyblk->keyvalue->length);
printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype,
keyblk->keyvalue->length);
for (i=0; i < keyblk->keyvalue->length; i++)
{
printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
......@@ -587,21 +839,52 @@ print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
}
/* Display contents of krb5_principal_data struct, for debugging
** (krb5_principal is typedef'd == krb5_principal_data *)
*/
void
print_krb5_princ(char *label, krb5_principal_data *princ)
{
int i, j;
printf("%s principal Realm: ", label);
if (princ == NULL) return;
for (i=0; i < princ->realm.length; i++) putchar(princ->realm.data[i]);
printf(" (nametype %d) has %d strings:\n", princ->type,princ->length);
for (i=0; i < princ->length; i++)
{
printf("\t%d [%d]: ", i, princ->data[i].length);
for (j=0; j < princ->data[i].length; j++) {
putchar(princ->data[i].data[j]);
}
printf("\n");
}
return;
}
/* Given krb5 service (typically "kssl") and hostname in kssl_ctx,
** Create Kerberos AP_REQ message for SSL Client.
** Return encrypted Kerberos ticket for service @ hostname.
** If authenp is non-NULL, also return encrypted authenticator,
** whose data should be freed by caller.
** (Originally was: Create Kerberos AP_REQ message for SSL Client.)
**
** 19990628 VRS Started.
** 19990628 VRS Started; Returns Kerberos AP_REQ message.
** 20010409 VRS Modified for RFC2712; Returns enc tkt.
** 20010606 VRS May also return optional authenticator.
*/
krb5_error_code
kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
/* OUT */ krb5_data *krb5_app_req, KSSL_ERR *kssl_err)
/* OUT */ krb5_data **enc_ticketp,
/* UPDATE */ krb5_data *authenp,
/* OUT */ KSSL_ERR *kssl_err)
{
krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
krb5_context krb5context = NULL;
krb5_auth_context krb5auth_context = NULL;
krb5_ccache krb5ccdef = NULL;
krb5_creds krb5creds, *krb5credsp = NULL;
krb5_data krb5in_data;
krb5_data krb5_app_req;
kssl_err_set(kssl_err, 0, "");
memset((char *)&krb5creds, 0, sizeof(krb5creds));
......@@ -635,7 +918,8 @@ kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
"krb5_sname_to_principal() fails for %s/%s\n",
kssl_ctx->service_host,
(kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC);
(kssl_ctx->service_name)? kssl_ctx->service_name:
KRB5SVC);
kssl_err->reason = SSL_R_KRB5_C_INIT;
goto err;
}
......@@ -663,26 +947,65 @@ kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
goto err;
}
krb5in_data.data = NULL;
krb5in_data.length = 0;
*enc_ticketp = &krb5credsp->ticket;
#ifdef KRB5_HEIMDAL
kssl_ctx->enctype = krb5credsp->session.keytype;
#else
kssl_ctx->enctype = krb5credsp->keyblock.enctype;
#endif
krb5rc = KRB5KRB_ERR_GENERIC;
/* caller should free data of krb5_app_req */
if ((krb5rc = krb5_mk_req_extended(krb5context, &krb5auth_context,
0, &krb5in_data, krb5credsp, krb5_app_req)) != 0)
/* 20010406 VRS deleted for real KerberosWrapper
** 20010605 VRS reinstated to offer Authenticator to KerberosWrapper
*/
krb5_app_req.length = 0;
if (authenp)
{
kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
"krb5_mk_req_extended() fails.\n");
goto err;
krb5_data krb5in_data;
unsigned char *p;
long arlen;
KRB5_APREQBODY *ap_req;
authenp->length = 0;
krb5in_data.data = NULL;
krb5in_data.length = 0;
if ((krb5rc = krb5_mk_req_extended(krb5context,
&krb5auth_context, 0, &krb5in_data, krb5credsp,
&krb5_app_req)) != 0)
{
kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
"krb5_mk_req_extended() fails.\n");
goto err;
}
arlen = krb5_app_req.length;
p = krb5_app_req.data;
ap_req = (KRB5_APREQBODY *) d2i_KRB5_APREQ(NULL, &p, arlen);
if (ap_req)
{
authenp->length = i2d_KRB5_ENCDATA(
ap_req->authenticator, NULL);
if (authenp->length &&
(authenp->data = malloc(authenp->length)))
{
unsigned char *p = authenp->data;
authenp->length = i2d_KRB5_ENCDATA(
ap_req->authenticator, &p);
}
}
if (ap_req) KRB5_APREQ_free((KRB5_APREQ *) ap_req);
if (krb5_app_req.length) krb5_xfree(krb5_app_req.data);
}
#ifdef KRB5_HEIMDAL
else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
{
kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
"kssl_ctx_setkey() fails.\n");
}
#else
else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
{
kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
"kssl_ctx_setkey() fails.\n");
......@@ -695,14 +1018,102 @@ kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
kssl_ctx_show(kssl_ctx);
#endif /* KSSL_DEBUG */
if (krb5creds.client) krb5_free_principal(krb5context, krb5creds.client);
if (krb5creds.server) krb5_free_principal(krb5context, krb5creds.server);
if (krb5auth_context) krb5_auth_con_free(krb5context, krb5auth_context);
if (krb5creds.client) krb5_free_principal(krb5context,
krb5creds.client);
if (krb5creds.server) krb5_free_principal(krb5context,
krb5creds.server);
if (krb5auth_context) krb5_auth_con_free(krb5context,
krb5auth_context);
if (krb5context) krb5_free_context(krb5context);
return (krb5rc);
}
/* Given d2i_-decoded asn1ticket, allocate and return a new krb5_ticket.
** Return Kerberos error code and kssl_err struct on error.
** Allocates krb5_ticket and krb5_principal; caller should free these.
**
** 20010410 VRS Implemented krb5_decode_ticket() as
** old_krb5_decode_ticket(). Missing from MIT1.0.6.
** 20010615 VRS Re-cast as openssl/asn1 d2i_*() functions.
** Re-used some of the old krb5_decode_ticket()
** code here. This tkt should alloc/free just
** like the real thing.
*/
krb5_error_code
kssl_TKT2tkt( /* IN */ krb5_context krb5context,
/* IN */ KRB5_TKTBODY *asn1ticket,
/* OUT */ krb5_ticket **krb5ticket,
/* OUT */ KSSL_ERR *kssl_err )
{
krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
krb5_ticket *new5ticket = NULL;
ASN1_GENERALSTRING *gstr_svc, *gstr_host;
*krb5ticket = NULL;
if (asn1ticket == NULL || asn1ticket->realm == NULL ||
asn1ticket->sname == NULL ||
asn1ticket->sname->namestring == NULL ||
asn1ticket->sname->namestring->num < 2)
{
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"Null field in asn1ticket.\n");
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
return KRB5KRB_ERR_GENERIC;
}
if ((new5ticket = (krb5_ticket *) calloc(1, sizeof(krb5_ticket)))==NULL)
{
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"Unable to allocate new krb5_ticket.\n");
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
return ENOMEM; /* or KRB5KRB_ERR_GENERIC; */
}
gstr_svc = (ASN1_GENERALSTRING*)asn1ticket->sname->namestring->data[0];
gstr_host = (ASN1_GENERALSTRING*)asn1ticket->sname->namestring->data[1];
if ((krb5rc = kssl_build_principal_2(krb5context,
&new5ticket->server,
asn1ticket->realm->length, asn1ticket->realm->data,
gstr_svc->length, gstr_svc->data,
gstr_host->length, gstr_host->data)) != 0)
{
free(new5ticket);
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"Error building ticket server principal.\n");
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
return krb5rc; /* or KRB5KRB_ERR_GENERIC; */
}
krb5_princ_type(krb5context, new5ticket->server) =
asn1ticket->sname->nametype->data[0];
new5ticket->enc_part.enctype = asn1ticket->encdata->etype->data[0];
new5ticket->enc_part.kvno = asn1ticket->encdata->kvno->data[0];
new5ticket->enc_part.ciphertext.length =
asn1ticket->encdata->cipher->length;
if ((new5ticket->enc_part.ciphertext.data =
calloc(1, asn1ticket->encdata->cipher->length)) == NULL)
{
free(new5ticket);
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"Error allocating cipher in krb5ticket.\n");
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
return KRB5KRB_ERR_GENERIC;
}
else
{
memcpy(new5ticket->enc_part.ciphertext.data,
asn1ticket->encdata->cipher->data,
asn1ticket->encdata->cipher->length);
}
*krb5ticket = new5ticket;
return 0;
}
/* Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
** and krb5 AP_REQ message & message length,
** Return Kerberos session key and client principle
......@@ -711,24 +1122,27 @@ kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
** 19990702 VRS Started.
*/
krb5_error_code
kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
/* IN */ char *msg, int msglen,
/* OUT */ KSSL_ERR *kssl_err )
kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
/* IN */ krb5_data *indata,
/* OUT */ krb5_ticket_times *ttimes,
/* OUT */ KSSL_ERR *kssl_err )
{
krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
static krb5_context krb5context = NULL;
static krb5_auth_context krb5auth_context = NULL;
krb5_ticket *krb5ticket = NULL;
KRB5_TKTBODY *asn1ticket = NULL;
unsigned char *p;
krb5_keytab krb5keytab = NULL;
krb5_keytab_entry kt_entry;
krb5_principal krb5server;
krb5_data krb5in_data;
krb5_flags ap_option;
kssl_err_set(kssl_err, 0, "");
if (!kssl_ctx)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n");
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
"No kssl_ctx defined.\n");
goto err;
}
......@@ -792,21 +1206,89 @@ kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
}
/* Actual Kerberos5 krb5_recvauth() has initial conversation here
** o check KRB5_SENDAUTH_BADAUTHVERS unless KRB5_RECVAUTH_SKIP_VERSION
** o check KRB5_SENDAUTH_BADAUTHVERS
** unless KRB5_RECVAUTH_SKIP_VERSION
** o check KRB5_SENDAUTH_BADAPPLVERS
** o send "0" msg if all OK
*/
krb5in_data.data = msg;
krb5in_data.length = msglen;
if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context, &krb5in_data,
krb5server, krb5keytab, &ap_option, &krb5ticket)) != 0)
{
/* 20010411 was using AP_REQ instead of true KerberosWrapper
**
** if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
** &krb5in_data, krb5server, krb5keytab,
** &ap_option, &krb5ticket)) != 0) { Error }
*/
p = indata->data;
if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p,
(long) indata->length)) == NULL)
{
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"d2i_KRB5_TICKET() ASN.1 decode failure.\n");
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
goto err;
}
/* Was: krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0) */
if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket,
kssl_err)) != 0)
{
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"Error converting ASN.1 ticket to krb5_ticket.\n");
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
goto err;
}
if (! krb5_principal_compare(krb5context, krb5server,
krb5ticket->server)) {
krb5rc = KRB5_PRINC_NOMATCH;
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"server principal != ticket principal\n");
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
goto err;
}
if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
krb5ticket->server, krb5ticket->enc_part.kvno,
krb5ticket->enc_part.enctype, &kt_entry)) != 0) {
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"krb5_rd_req() fails with %x.\n", krb5rc);
"krb5_kt_get_entry() fails with %x.\n", krb5rc);
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
goto err;
}
if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key,
krb5ticket)) != 0) {
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"krb5_decrypt_tkt_part() failed.\n");
kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
goto err;
}
else {
krb5_kt_free_entry(krb5context, &kt_entry);
#ifdef KSSL_DEBUG
{
int i; krb5_address **paddr = krb5ticket->enc_part2->caddrs;
printf("Decrypted ticket fields:\n");
printf("\tflags: %X, transit-type: %X",
krb5ticket->enc_part2->flags,
krb5ticket->enc_part2->transited.tr_type);
print_krb5_data("\ttransit-data: ",
&(krb5ticket->enc_part2->transited.tr_contents));
printf("\tcaddrs: %p, authdata: %p\n",
krb5ticket->enc_part2->caddrs,
krb5ticket->enc_part2->authorization_data);
printf("\tcaddrs:\n");
for (i=0; paddr[i] != NULL; i++)
{ krb5_data d;
d.length=paddr[i]->length; d.data=paddr[i]->contents;
print_krb5_data("\t\tIP: ", &d);
}
printf("\tstart/auth/end times: %d / %d / %d\n",
krb5ticket->enc_part2->times.starttime,
krb5ticket->enc_part2->times.authtime,
krb5ticket->enc_part2->times.endtime);
}
#endif /* KSSL_DEBUG */
}
krb5rc = KRB5_NO_TKT_SUPPLIED;
if (!krb5ticket || !krb5ticket->enc_part2 ||
......@@ -829,13 +1311,26 @@ kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
"kssl_ctx_setkey() fails.\n");
}
else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID)
{
krb5rc = KRB5KRB_AP_ERR_TKT_INVALID;
kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
"invalid ticket from krb5_rd_req.\n");
}
else krb5rc = 0;
kssl_ctx->enctype = krb5ticket->enc_part.enctype;
ttimes->authtime = krb5ticket->enc_part2->times.authtime;
ttimes->starttime = krb5ticket->enc_part2->times.starttime;
ttimes->endtime = krb5ticket->enc_part2->times.endtime;
ttimes->renew_till = krb5ticket->enc_part2->times.renew_till;
err:
#ifdef KSSL_DEBUG
kssl_ctx_show(kssl_ctx);
#endif /* KSSL_DEBUG */
if (asn1ticket) KRB5_TICKET_free((KRB5_TICKET *) asn1ticket);
if (krb5keytab) krb5_kt_close(krb5context, krb5keytab);
if (krb5ticket) krb5_free_ticket(krb5context, krb5ticket);
if (krb5server) krb5_free_principal(krb5context, krb5server);
......@@ -860,7 +1355,8 @@ kssl_ctx_free(KSSL_CTX *kssl_ctx)
{
if (kssl_ctx == NULL) return kssl_ctx;
if (kssl_ctx->key) memset(kssl_ctx->key, 0, kssl_ctx->length);
if (kssl_ctx->key) memset(kssl_ctx->key, 0,
kssl_ctx->length);
if (kssl_ctx->key) free(kssl_ctx->key);
if (kssl_ctx->client_princ) free(kssl_ctx->client_princ);
if (kssl_ctx->service_host) free(kssl_ctx->service_host);
......@@ -953,6 +1449,10 @@ kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
krb5_error_code
kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
{
int length;
krb5_enctype enctype;
krb5_octet FAR *contents = NULL;
if (!kssl_ctx) return KSSL_CTX_ERR;
if (kssl_ctx->key)
......@@ -963,8 +1463,18 @@ kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
if (session)
{
kssl_ctx->enctype = session->enctype;
kssl_ctx->length = session->length;
#ifdef KRB5_HEIMDAL
length = session->keyvalue->length;
enctype = session->keytype;
contents = session->keyvalue->contents;
#else
length = session->length;
enctype = session->enctype;
contents = session->contents;
#endif
kssl_ctx->enctype = enctype;
kssl_ctx->length = length;
}
else
{
......@@ -980,7 +1490,7 @@ kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
return KSSL_CTX_ERR;
}
else
memcpy(kssl_ctx->key, session->contents, session->length);
memcpy(kssl_ctx->key, contents, length);
return KSSL_CTX_OK;
}
......@@ -1026,11 +1536,269 @@ void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
#ifdef KRB5_HEIMDAL
data->length = 0;
free(data->if (data->data) data);
#elif defined(KRB5_MIT_OLD11)
if (data->data) {
krb5_xfree(data->data);
data->data = 0;
}
#else
krb5_free_data_contents(NULL, data);
#endif
}
/* Helper function for kssl_validate_times().
** We need context->clockskew, but krb5_context is an opaque struct.
** So we try to sneek the clockskew out through the replay cache.
** If that fails just return a likely default (300 seconds).
*/
krb5_deltat get_rc_clockskew(krb5_context context)
{
krb5_rcache rc;
krb5_deltat clockskew;
if (krb5_rc_default(context, &rc)) return KSSL_CLOCKSKEW;
if (krb5_rc_initialize(context, rc, 0)) return KSSL_CLOCKSKEW;
if (krb5_rc_get_lifespan(context, rc, &clockskew)) {
clockskew = KSSL_CLOCKSKEW;
}
(void) krb5_rc_destroy(context, rc);
return clockskew;
}
/* kssl_validate_times() combines (and more importantly exposes)
** the MIT KRB5 internal function krb5_validate_times() and the
** in_clock_skew() macro. The authenticator client time is checked
** to be within clockskew secs of the current time and the current
** time is checked to be within the ticket start and expire times.
** Either check may be omitted by supplying a NULL value.
** Returns 0 for valid times, SSL_R_KRB5* error codes otherwise.
** See Also: (Kerberos source)/krb5/lib/krb5/krb/valid_times.c
** 20010420 VRS
*/
krb5_error_code kssl_validate_times( krb5_timestamp atime,
krb5_ticket_times *ttimes)
{
krb5_deltat skew;
krb5_timestamp start, now;
krb5_error_code rc;
krb5_context context;
if ((rc = krb5_init_context(&context))) return SSL_R_KRB5_S_BAD_TICKET;
skew = get_rc_clockskew(context);
if ((rc = krb5_timeofday(context,&now))) return SSL_R_KRB5_S_BAD_TICKET;
krb5_free_context(context);
if (atime && labs(atime - now) >= skew) return SSL_R_KRB5_S_TKT_SKEW;
if (! ttimes) return 0;
start = (ttimes->starttime != 0)? ttimes->starttime: ttimes->authtime;
if (start - now > skew) return SSL_R_KRB5_S_TKT_NYV;
if ((now - ttimes->endtime) > skew) return SSL_R_KRB5_S_TKT_EXPIRED;
#ifdef KSSL_DEBUG
printf("kssl_validate_times: %d |<- | %d - %d | < %d ->| %d\n",
start, atime, now, skew, ttimes->endtime);
#endif /* KSSL_DEBUG */
return 0;
}
/* Decode and decrypt given DER-encoded authenticator, then pass
** authenticator ctime back in *atimep (or 0 if time unavailable).
** Returns krb5_error_code and kssl_err on error. A NULL
** authenticator (authentp->length == 0) is not considered an error.
** Note that kssl_check_authent() makes use of the KRB5 session key;
** you must call kssl_sget_tkt() to get the key before calling this routine.
*/
krb5_error_code kssl_check_authent(
/* IN */ KSSL_CTX *kssl_ctx,
/* IN */ krb5_data *authentp,
/* OUT */ krb5_timestamp *atimep,
/* OUT */ KSSL_ERR *kssl_err )
{
krb5_error_code krb5rc = 0;
KRB5_ENCDATA *dec_authent = NULL;
KRB5_AUTHENTBODY *auth = NULL;
krb5_enctype enctype;
EVP_CIPHER_CTX ciph_ctx;
EVP_CIPHER *enc = NULL;
unsigned char iv[EVP_MAX_IV_LENGTH];
unsigned char *p, *unenc_authent, *tbuf = NULL;
int padl, outl, unencbufsize;
struct tm tm_time, *tm_l, *tm_g;
time_t now, tl, tg, tz_offset;
*atimep = 0;
kssl_err_set(kssl_err, 0, "");
#ifndef KRB5CHECKAUTH
authentp = NULL;
#else
#if KRB5CHECKAUTH == 0
authentp = NULL;
#endif
#endif /* KRB5CHECKAUTH */
if (authentp == NULL || authentp->length == 0) return 0;
#ifdef KSSL_DEBUG
printf("kssl_check_authent: authenticator[%d]:\n",authentp->length);
p = authentp->data;
for (padl=0; padl < authentp->length; padl++) printf("%02x ",p[padl]);
printf("\n");
#endif /* KSSL_DEBUG */
unencbufsize = 2 * authentp->length;
if ((unenc_authent = calloc(1, unencbufsize)) == NULL)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
"Unable to allocate authenticator buffer.\n");
krb5rc = KRB5KRB_ERR_GENERIC;
goto err;
}
p = authentp->data;
if ((dec_authent = d2i_KRB5_ENCDATA(NULL, &p,
(long) authentp->length)) == NULL)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
"Error decoding authenticator.\n");
krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
goto err;
}
enctype = dec_authent->etype->data[0]; /* should = kssl_ctx->enctype */
enc = kssl_map_enc(enctype);
memset(iv, 0, EVP_MAX_IV_LENGTH); /* per RFC 1510 */
EVP_DecryptInit(&ciph_ctx, enc, kssl_ctx->key, iv);
EVP_DecryptUpdate(&ciph_ctx, unenc_authent, &outl,
dec_authent->cipher->data, dec_authent->cipher->length);
if (outl > unencbufsize)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
"Buffer overflow decrypting authenticator.\n");
krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
goto err;
}
EVP_DecryptFinal(&ciph_ctx, &(unenc_authent[outl]), &padl);
outl += padl;
if (outl > unencbufsize)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
"Buffer overflow decrypting authenticator.\n");
krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
goto err;
}
EVP_CIPHER_CTX_cleanup(&ciph_ctx);
#ifdef KSSL_DEBUG
printf("kssl_check_authent: decrypted authenticator[%d] =\n", outl);
for (padl=0; padl < outl; padl++) printf("%02x ",unenc_authent[padl]);
printf("\n");
#endif /* KSSL_DEBUG */
if ((p = kssl_skip_confound(enctype, unenc_authent)) == NULL)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
"confounded by authenticator.\n");
krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
goto err;
}
outl -= p - unenc_authent;
if ((auth = (KRB5_AUTHENTBODY *) d2i_KRB5_AUTHENT(NULL, &p,
(long) outl))==NULL)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
"Error decoding authenticator body.\n");
krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
goto err;
}
if ((tbuf = calloc(1, auth->ctime->length + 1)) == NULL)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
"Unable to allocate atime buffer.\n");
krb5rc = KRB5KRB_ERR_GENERIC;
goto err;
}
else strncpy(tbuf, auth->ctime->data, auth->ctime->length);
if (strptime(tbuf, "%Y%m%d%H%M%S", &tm_time) != NULL)
{
now = time(&now);
tm_l = localtime(&now); tl = mktime(tm_l);
tm_g = gmtime(&now); tg = mktime(tm_g);
tz_offset = tg - tl;
*atimep = mktime(&tm_time) - tz_offset;
}
#ifdef KSSL_DEBUG
printf("kssl_check_authent: client time %s = %d\n", tbuf, *atimep);
#endif /* KSSL_DEBUG */
err:
if (tbuf) free(tbuf);
if (auth) KRB5_AUTHENT_free((KRB5_AUTHENT *) auth);
if (dec_authent) KRB5_ENCDATA_free(dec_authent);
if (unenc_authent) free(unenc_authent);
return krb5rc;
}
/* Replaces krb5_build_principal_ext(), with varargs length == 2 (svc, host),
** because I dont't know how to stub varargs.
** Returns krb5_error_code == ENOMEM on alloc error, otherwise
** passes back newly constructed principal, which should be freed by caller.
*/
krb5_error_code kssl_build_principal_2(
/* UPDATE */ krb5_context context,
/* OUT */ krb5_principal *princ,
/* IN */ int rlen, const char *realm,
/* IN */ int slen, const char *svc,
/* IN */ int hlen, const char *host)
{
krb5_data *p_data = NULL;
krb5_principal new_p = NULL;
char *new_r = NULL;
if ((p_data = (krb5_data *) calloc(2, sizeof(krb5_data))) == NULL ||
(new_p = (krb5_principal) calloc(1, sizeof(krb5_principal_data)))
== NULL) goto err;
new_p->length = 2;
new_p->data = p_data;
if ((new_r = calloc(1, rlen + 1)) == NULL) goto err;
memcpy(new_r, realm, rlen);
krb5_princ_set_realm_length(context, new_p, rlen);
krb5_princ_set_realm_data(context, new_p, new_r);
if ((new_p->data[0].data = calloc(1, slen + 1)) == NULL) goto err;
memcpy(new_p->data[0].data, svc, slen);
new_p->data[0].length = slen;
if ((new_p->data[1].data = calloc(1, hlen + 1)) == NULL) goto err;
memcpy(new_p->data[1].data, host, hlen);
new_p->data[1].length = hlen;
krb5_princ_type(context, new_p) = KRB5_NT_UNKNOWN;
*princ = new_p;
return 0;
err:
if (new_p && new_p[0].data) free(new_p[0].data);
if (new_p && new_p[1].data) free(new_p[1].data);
if (new_p) free(new_p);
if (new_r) free(new_r);
return ENOMEM;
}
#else /* !OPENSSL_NO_KRB5 */
#if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS)
......
......@@ -96,6 +96,17 @@ typedef unsigned char krb5_octet;
#define KRB5KEYTAB "/etc/krb5.keytab"
#endif
#ifndef KRB5SENDAUTH
#define KRB5SENDAUTH 1
#endif
#ifndef KRB5CHECKAUTH
#define KRB5CHECKAUTH 1
#endif
#ifndef KSSL_CLOCKSKEW
#define KSSL_CLOCKSKEW 300;
#endif
#define KSSL_ERR_MAX 255
typedef struct kssl_err_st {
......@@ -139,6 +150,8 @@ void print_krb5_keyblock(char *label, krb5_keyblock *keyblk);
char *kstring(char *string);
char *knumber(int len, krb5_octet *contents);
EVP_CIPHER *kssl_map_enc(krb5_enctype enctype);
/* Public (for use by applications that use OpenSSL with Kerberos 5 support */
krb5_error_code kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text);
......@@ -147,13 +160,21 @@ KSSL_CTX *kssl_ctx_free(KSSL_CTX *kssl_ctx);
void kssl_ctx_show(KSSL_CTX *kssl_ctx);
krb5_error_code kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
krb5_data *realm, krb5_data *entity);
krb5_error_code kssl_cget_tkt(KSSL_CTX *kssl_ctx, krb5_data *ap_req,
KSSL_ERR *kssl_err);
krb5_error_code kssl_sget_tkt(KSSL_CTX *kssl_ctx, char *msg, int msglen,
KSSL_ERR *kssl_err);
krb5_error_code kssl_cget_tkt(KSSL_CTX *kssl_ctx, krb5_data **enc_tktp,
krb5_data *authenp, KSSL_ERR *kssl_err);
krb5_error_code kssl_sget_tkt(KSSL_CTX *kssl_ctx, krb5_data *indata,
krb5_ticket_times *ttimes, KSSL_ERR *kssl_err);
krb5_error_code kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session);
void kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text);
void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data);
krb5_error_code kssl_build_principal_2(krb5_context context,
krb5_principal *princ, int rlen, const char *realm,
int slen, const char *svc, int hlen, const char *host);
krb5_error_code kssl_validate_times(krb5_timestamp atime,
krb5_ticket_times *ttimes);
krb5_error_code kssl_check_authent(KSSL_CTX *kssl_ctx, krb5_data *authentp,
krb5_timestamp *atimep, KSSL_ERR *kssl_err);
unsigned char *kssl_skip_confound(krb5_enctype enctype, unsigned char *authn);
#ifdef __cplusplus
}
......
......@@ -785,13 +785,13 @@ static int ssl3_get_server_certificate(SSL *s)
* certificate, which we don't include in s3_srvr.c */
x=sk_X509_value(sk,0);
sk=NULL;
/* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end */
/* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end*/
pkey=X509_get_pubkey(x);
/* VRS: allow null cert if auth == KRB5 */
need_cert =
((s->s3->tmp.new_cipher->algorithms & (SSL_MKEY_MASK|SSL_AUTH_MASK))
need_cert = ((s->s3->tmp.new_cipher->algorithms
& (SSL_MKEY_MASK|SSL_AUTH_MASK))
== (SSL_aKRB5|SSL_kKRB5))? 0: 1;
#ifdef KSSL_DEBUG
......@@ -801,11 +801,12 @@ static int ssl3_get_server_certificate(SSL *s)
s->s3->tmp.new_cipher->algorithms, need_cert);
#endif /* KSSL_DEBUG */
if (need_cert && ((pkey == NULL) || EVP_PKEY_missing_parameters(pkey)))
if (need_cert && ((pkey == NULL) || EVP_PKEY_missing_parameters(pkey)))
{
x=NULL;
al=SSL3_AL_FATAL;
SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
goto f_err;
}
......@@ -814,7 +815,8 @@ static int ssl3_get_server_certificate(SSL *s)
{
x=NULL;
al=SSL3_AL_FATAL;
SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_UNKNOWN_CERTIFICATE_TYPE);
SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
SSL_R_UNKNOWN_CERTIFICATE_TYPE);
goto f_err;
}
......@@ -1427,65 +1429,121 @@ static int ssl3_send_client_key_exchange(SSL *s)
{
krb5_error_code krb5rc;
KSSL_CTX *kssl_ctx = s->kssl_ctx;
krb5_data krb5_ap_req;
/* krb5_data krb5_ap_req; */
krb5_data *enc_ticket;
krb5_data authenticator, *authp = NULL;
EVP_CIPHER_CTX ciph_ctx;
EVP_CIPHER *enc = NULL;
unsigned char iv[EVP_MAX_IV_LENGTH];
unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
unsigned char epms[SSL_MAX_MASTER_KEY_LENGTH
+ EVP_MAX_IV_LENGTH];
int padl, outl = sizeof(epms);
#ifdef KSSL_DEBUG
printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
l, SSL_kKRB5);
#endif /* KSSL_DEBUG */
/*
** Tried to send random tmp_buf[] as PMS in Kerberos ticket
** by passing krb5_mk_req_extended(ctx,authctx,opts, tmp_buf, ...)
** but: I can't retrieve the PMS on the other side! There is
** some indication in the krb5 source that this is only used
** to generate a checksum. OTOH, the Tung book shows data
** ("GET widget01.txt") being passed in krb5_mk_req_extended()
** by way of krb5_sendauth(). I don't get it.
** Until Kerberos goes 3DES, the big PMS secret would only be
** encrypted in 1-DES anyway. So losing the PMS shouldn't be
** a big deal.
*/
krb5rc = kssl_cget_tkt(kssl_ctx, &krb5_ap_req,
&kssl_err);
authp = NULL;
#ifdef KRB5SENDAUTH
if (KRB5SENDAUTH) authp = &authenticator;
#endif /* KRB5SENDAUTH */
krb5rc = kssl_cget_tkt(kssl_ctx, &enc_ticket, authp,
&kssl_err);
enc = kssl_map_enc(kssl_ctx->enctype);
#ifdef KSSL_DEBUG
{
printf("kssl_cget_tkt rtn %d\n", krb5rc);
kssl_ctx_show(kssl_ctx);
if (krb5rc && kssl_err.text)
printf("kssl_cget_tkt kssl_err=%s\n", kssl_err.text);
printf("kssl_cget_tkt kssl_err=%s\n", kssl_err.text);
}
#endif /* KSSL_DEBUG */
if (krb5rc)
{
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, kssl_err.reason);
ssl3_send_alert(s,SSL3_AL_FATAL,
SSL_AD_HANDSHAKE_FAILURE);
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
kssl_err.reason);
goto err;
}
/* Send ticket (copy to *p, set n = length)
*/
n = krb5_ap_req.length;
memcpy(p, krb5_ap_req.data, krb5_ap_req.length);
if (krb5_ap_req.data)
kssl_krb5_free_data_contents(NULL,&krb5_ap_req);
/* 19991013 VRS - 3DES is kind of bogus here,
** at least until Kerberos supports 3DES. The only
** real secret is the 8-byte Kerberos session key;
** the other key material ((s->) client_random, server_random)
** could be sniffed. Mixing in these nonces should help
** protect against replay attacks, however.
**
** Alternate code for Kerberos Purists:
/* 20010406 VRS - Earlier versions used KRB5 AP_REQ
** in place of RFC 2712 KerberosWrapper, as in:
**
** Send ticket (copy to *p, set n = length)
** n = krb5_ap_req.length;
** memcpy(p, krb5_ap_req.data, krb5_ap_req.length);
** if (krb5_ap_req.data)
** kssl_krb5_free_data_contents(NULL,&krb5_ap_req);
**
** memcpy(s->session->master_key, kssl_ctx->key, kssl_ctx->length);
** s->session->master_key_length = kssl_ctx->length;
*/
** Now using real RFC 2712 KerberosWrapper
** (Thanks to Simon Wilkinson <sxw@sxw.org.uk>)
** Note: 2712 "opaque" types are here replaced
** with a 2-byte length followed by the value.
** Example:
** KerberosWrapper= xx xx asn1ticket 0 0 xx xx encpms
** Where "xx xx" = length bytes. Shown here with
** optional authenticator omitted.
*/
/* KerberosWrapper.Ticket */
s2n(enc_ticket->length,p);
memcpy(p, enc_ticket->data, enc_ticket->length);
p+= enc_ticket->length;
n = enc_ticket->length + 2;
/* KerberosWrapper.Authenticator */
if (authp && authp->length)
{
s2n(authp->length,p);
memcpy(p, authp->data, authp->length);
p+= authp->length;
n+= authp->length + 2;
free(authp->data);
authp->data = NULL;
authp->length = 0;
}
else
{
s2n(0,p);/* null authenticator length */
n+=2;
}
if (RAND_bytes(tmp_buf,SSL_MAX_MASTER_KEY_LENGTH) <= 0)
goto err;
/* 20010420 VRS. Tried it this way; failed.
** EVP_EncryptInit(&ciph_ctx,enc, NULL,NULL);
** EVP_CIPHER_CTX_set_key_length(&ciph_ctx,
** kssl_ctx->length);
** EVP_EncryptInit(&ciph_ctx,NULL, key,iv);
*/
memset(iv, 0, EVP_MAX_IV_LENGTH); /* per RFC 1510 */
EVP_EncryptInit(&ciph_ctx,enc, kssl_ctx->key,iv);
EVP_EncryptUpdate(&ciph_ctx,epms,&outl,tmp_buf,
SSL_MAX_MASTER_KEY_LENGTH);
EVP_EncryptFinal(&ciph_ctx,&(epms[outl]),&padl);
outl += padl;
EVP_CIPHER_CTX_cleanup(&ciph_ctx);
/* KerberosWrapper.EncryptedPreMasterSecret */
s2n(outl,p);
memcpy(p, epms, outl);
p+=outl;
n+=outl + 2;
s->session->master_key_length=
s->method->ssl3_enc->generate_master_secret(s,
s->session->master_key, kssl_ctx->key,kssl_ctx->length);
s->session->master_key,
tmp_buf, SSL_MAX_MASTER_KEY_LENGTH);
memset(tmp_buf, 0, SSL_MAX_MASTER_KEY_LENGTH);
memset(epms, 0, outl);
}
#endif
#ifndef OPENSSL_NO_DH
......
......@@ -66,6 +66,7 @@
#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/krb5_asn.h>
#include "ssl_locl.h"
#ifndef OPENSSL_NO_KRB5
......@@ -1452,13 +1453,46 @@ static int ssl3_get_client_key_exchange(SSL *s)
#ifndef OPENSSL_NO_KRB5
if (l & SSL_kKRB5)
{
krb5_error_code krb5rc;
KSSL_CTX *kssl_ctx = s->kssl_ctx;
krb5_error_code krb5rc;
krb5_data enc_ticket;
krb5_data authenticator;
krb5_data enc_pms;
KSSL_CTX *kssl_ctx = s->kssl_ctx;
EVP_CIPHER_CTX ciph_ctx;
EVP_CIPHER *enc = NULL;
unsigned char iv[EVP_MAX_IV_LENGTH];
unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH];
int padl, outl = sizeof(pms);
krb5_timestamp authtime = 0;
krb5_ticket_times ttimes;
if (!kssl_ctx) kssl_ctx = kssl_ctx_new();
if ((krb5rc = kssl_sget_tkt(kssl_ctx,
s->init_buf->data, s->init_buf->length,
&kssl_err)) != 0)
n2s(p,i);
enc_ticket.length = i;
enc_ticket.data = p;
p+=enc_ticket.length;
n2s(p,i);
authenticator.length = i;
authenticator.data = p;
p+=authenticator.length;
n2s(p,i);
enc_pms.length = i;
enc_pms.data = p;
p+=enc_pms.length;
if (n != enc_ticket.length + authenticator.length +
enc_pms.length + 6)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
SSL_R_DATA_LENGTH_TOO_LONG);
goto err;
}
if ((krb5rc = kssl_sget_tkt(kssl_ctx, &enc_ticket, &ttimes,
&kssl_err)) != 0)
{
#ifdef KSSL_DEBUG
printf("kssl_sget_tkt rtn %d [%d]\n",
......@@ -1471,34 +1505,71 @@ static int ssl3_get_client_key_exchange(SSL *s)
goto err;
}
/* Note: no authenticator is not considered an error,
** but will return authtime == 0.
*/
if ((krb5rc = kssl_check_authent(kssl_ctx, &authenticator,
&authtime, &kssl_err)) != 0)
{
#ifdef KSSL_DEBUG
printf("kssl_check_authent rtn %d [%d]\n",
krb5rc, kssl_err.reason);
if (kssl_err.text)
printf("kssl_err text= %s\n", kssl_err.text);
#endif /* KSSL_DEBUG */
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
kssl_err.reason);
goto err;
}
if ((krb5rc = kssl_validate_times(authtime, &ttimes)) != 0)
{
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, krb5rc);
goto err;
}
#ifdef KSSL_DEBUG
kssl_ctx_show(kssl_ctx);
#endif /* KSSL_DEBUG */
/* 19991013 VRS - 3DES is kind of bogus here,
** at least until Kerberos supports 3DES. The only
** real secret is the 8-byte Kerberos session key;
** the other key material (client_random, server_random)
** could be sniffed. Nonces may help against replays though.
**
** Alternate code for Kerberos Purists:
**
** memcpy(s->session->master_key, kssl_ctx->key, kssl_ctx->length);
** s->session->master_key_length = kssl_ctx->length;
*/
enc = kssl_map_enc(kssl_ctx->enctype);
memset(iv, 0, EVP_MAX_IV_LENGTH); /* per RFC 1510 */
EVP_DecryptInit(&ciph_ctx,enc,kssl_ctx->key,iv);
EVP_DecryptUpdate(&ciph_ctx, pms,&outl,
enc_pms.data, enc_pms.length);
if (outl > SSL_MAX_MASTER_KEY_LENGTH)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
SSL_R_DATA_LENGTH_TOO_LONG);
goto err;
}
EVP_DecryptFinal(&ciph_ctx,&(pms[outl]),&padl);
outl += padl;
if (outl > SSL_MAX_MASTER_KEY_LENGTH)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
SSL_R_DATA_LENGTH_TOO_LONG);
goto err;
}
EVP_CIPHER_CTX_cleanup(&ciph_ctx);
s->session->master_key_length=
s->method->ssl3_enc->generate_master_secret(s,
s->session->master_key, kssl_ctx->key, kssl_ctx->length);
/* Was doing kssl_ctx_free() here, but it caused problems for apache.
** kssl_ctx = kssl_ctx_free(kssl_ctx);
** if (s->kssl_ctx) s->kssl_ctx = NULL;
s->session->master_key, pms, outl);
/* Was doing kssl_ctx_free() here,
** but it caused problems for apache.
** kssl_ctx = kssl_ctx_free(kssl_ctx);
** if (s->kssl_ctx) s->kssl_ctx = NULL;
*/
}
else
#endif /* OPENSSL_NO_KRB5 */
{
al=SSL_AD_HANDSHAKE_FAILURE;
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNKNOWN_CIPHER_TYPE);
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
SSL_R_UNKNOWN_CIPHER_TYPE);
goto f_err;
}
......
......@@ -1459,13 +1459,17 @@ void ERR_load_SSL_strings(void);
#define SSL_R_INVALID_COMMAND 280
#define SSL_R_INVALID_PURPOSE 278
#define SSL_R_INVALID_TRUST 279
#define SSL_R_KRB5 1104
#define SSL_R_KRB5_C_CC_PRINC 1094
#define SSL_R_KRB5_C_GET_CRED 1095
#define SSL_R_KRB5_C_INIT 1096
#define SSL_R_KRB5_C_MK_REQ 1097
#define SSL_R_KRB5_S_BAD_TICKET 1098
#define SSL_R_KRB5_S_INIT 1099
#define SSL_R_KRB5_S_RD_REQ 1100
#define SSL_R_KRB5_S_RD_REQ 1108
#define SSL_R_KRB5_S_TKT_EXPIRED 1105
#define SSL_R_KRB5_S_TKT_NYV 1106
#define SSL_R_KRB5_S_TKT_SKEW 1107
#define SSL_R_LENGTH_MISMATCH 159
#define SSL_R_LENGTH_TOO_SHORT 160
#define SSL_R_LIBRARY_BUG 274
......
......@@ -273,13 +273,17 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{SSL_R_INVALID_COMMAND ,"invalid command"},
{SSL_R_INVALID_PURPOSE ,"invalid purpose"},
{SSL_R_INVALID_TRUST ,"invalid trust"},
{SSL_R_KRB5_C_CC_PRINC ,"krb5 c cc princ"},
{SSL_R_KRB5_C_GET_CRED ,"krb5 c get cred"},
{SSL_R_KRB5_C_INIT ,"krb5 c init"},
{SSL_R_KRB5_C_MK_REQ ,"krb5 c mk req"},
{SSL_R_KRB5_S_BAD_TICKET ,"krb5 s bad ticket"},
{SSL_R_KRB5_S_INIT ,"krb5 s init"},
{SSL_R_KRB5_S_RD_REQ ,"krb5 s rd req"},
{SSL_R_KRB5 ,"krb5"},
{SSL_R_KRB5_C_CC_PRINC ,"krb5 client cc principal (no tkt?)"},
{SSL_R_KRB5_C_GET_CRED ,"krb5 client get cred"},
{SSL_R_KRB5_C_INIT ,"krb5 client init"},
{SSL_R_KRB5_C_MK_REQ ,"krb5 client mk_req (expired tkt?)"},
{SSL_R_KRB5_S_BAD_TICKET ,"krb5 server bad ticket"},
{SSL_R_KRB5_S_INIT ,"krb5 server init"},
{SSL_R_KRB5_S_RD_REQ ,"krb5 server rd_req (keytab perms?)"},
{SSL_R_KRB5_S_TKT_EXPIRED ,"krb5 server tkt expired"},
{SSL_R_KRB5_S_TKT_NYV ,"krb5 server tkt not yet valid"},
{SSL_R_KRB5_S_TKT_SKEW ,"krb5 server tkt skew"},
{SSL_R_LENGTH_MISMATCH ,"length mismatch"},
{SSL_R_LENGTH_TOO_SHORT ,"length too short"},
{SSL_R_LIBRARY_BUG ,"library bug"},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册