Beispiel #1
0
// InquireCredByMech implements gss_inquire_cred_by_mech API, as per
// https://tools.ietf.org/html/rfc2743#page-39. name must be .Release()-ed by
// the caller
func (lib *Lib) InquireCredByMech(credHandle *CredId, mechType *OID) (
	name *Name, initiatorLifetime time.Duration, acceptorLifetime time.Duration,
	credUsage CredUsage, err error) {

	min := C.OM_uint32(0)
	name = lib.NewName()
	ilife := C.OM_uint32(0)
	alife := C.OM_uint32(0)
	credUsage = CredUsage(0)

	maj := C.wrap_gss_inquire_cred_by_mech(lib.Fp_gss_inquire_cred_by_mech,
		&min,
		credHandle.C_gss_cred_id_t,
		mechType.C_gss_OID,
		&name.C_gss_name_t,
		&ilife,
		&alife,
		(*C.gss_cred_usage_t)(&credUsage))
	err = lib.stashLastStatus(maj, min)
	if err != nil {
		return nil, 0, 0, 0, err
	}

	return name,
		time.Duration(ilife) * time.Second,
		time.Duration(alife) * time.Second,
		credUsage,
		nil
}
Beispiel #2
0
// AcquireCred implements gss_acquire_cred API, as per
// https://tools.ietf.org/html/rfc2743#page-31. outputCredHandle, actualMechs
// must be .Release()-ed by the caller
func (lib *Lib) AcquireCred(desiredName *Name, timeReq time.Duration,
	desiredMechs *OIDSet, credUsage CredUsage) (outputCredHandle *CredId,
	actualMechs *OIDSet, timeRec time.Duration, err error) {

	min := C.OM_uint32(0)
	actualMechs = lib.NewOIDSet()
	outputCredHandle = lib.NewCredId()
	timerec := C.OM_uint32(0)

	maj := C.wrap_gss_acquire_cred(lib.Fp_gss_acquire_cred,
		&min,
		desiredName.C_gss_name_t,
		C.OM_uint32(timeReq.Seconds()),
		desiredMechs.C_gss_OID_set,
		C.gss_cred_usage_t(credUsage),
		&outputCredHandle.C_gss_cred_id_t,
		&actualMechs.C_gss_OID_set,
		&timerec)

	err = lib.stashLastStatus(maj, min)
	if err != nil {
		return nil, nil, 0, err
	}

	return outputCredHandle, actualMechs, time.Duration(timerec) * time.Second, nil
}
Beispiel #3
0
// InquireCred implements gss_inquire_cred API, as per
// https://tools.ietf.org/html/rfc2743#page-34. name and mechanisms must be
// .Release()-ed by the caller
func (lib *Lib) InquireCred(credHandle *CredId) (
	name *Name, lifetime time.Duration, credUsage CredUsage, mechanisms *OIDSet,
	err error) {

	min := C.OM_uint32(0)
	name = lib.NewName()
	life := C.OM_uint32(0)
	credUsage = CredUsage(0)
	mechanisms = lib.NewOIDSet()

	maj := C.wrap_gss_inquire_cred(lib.Fp_gss_inquire_cred,
		&min,
		credHandle.C_gss_cred_id_t,
		&name.C_gss_name_t,
		&life,
		(*C.gss_cred_usage_t)(&credUsage),
		&mechanisms.C_gss_OID_set)
	err = lib.stashLastStatus(maj, min)
	if err != nil {
		return nil, 0, 0, nil, err
	}

	return name,
		time.Duration(life) * time.Second,
		credUsage,
		mechanisms,
		nil
}
Beispiel #4
0
// Error returns a string representation of an Error object.
func (e *Error) Error() string {
	messages := []string{}
	nOther := 0
	context := C.OM_uint32(0)
	inquiry := C.OM_uint32(0)
	code_type := 0
	first := true

	if e.Major.RoutineError() == GSS_S_FAILURE {
		inquiry = e.Minor
		code_type = GSS_C_MECH_CODE
	} else {
		inquiry = C.OM_uint32(e.Major)
		code_type = GSS_C_GSS_CODE
	}

	for first || context != C.OM_uint32(0) {
		first = false
		min := C.OM_uint32(0)

		b, err := e.MakeBuffer(allocGSSAPI)
		if err != nil {
			break
		}

		// TODO: store a mech_type at the lib level?  Or context? For now GSS_C_NO_OID...
		maj := C.wrap_gss_display_status(
			e.Fp_gss_display_status,
			&min,
			inquiry,
			C.int(code_type),
			nil,
			&context,
			b.C_gss_buffer_t)

		err = e.MakeError(maj, min).GoError()
		if err != nil {
			nOther = nOther + 1
		}
		messages = append(messages, b.String())
		b.Release()
	}
	if nOther > 0 {
		messages = append(messages, fmt.Sprintf("additionally, %d conversions failed", nOther))
	}
	messages = append(messages, "")
	return strings.Join(messages, "\n")
}
Beispiel #5
0
// MakeOIDBytes makes an OID encapsulating a byte slice. Note that it does not
// duplicate the data, but rather it points to it directly.
func (lib *Lib) MakeOIDBytes(data []byte) (*OID, error) {
	oid := lib.NewOID()

	s := C.malloc(C.gss_OID_size) // s for struct
	if s == nil {
		return nil, ErrMallocFailed
	}
	C.memset(s, 0, C.gss_OID_size)

	l := C.size_t(len(data))
	e := C.malloc(l) // c for contents
	if e == nil {
		return nil, ErrMallocFailed
	}
	C.memmove(e, (unsafe.Pointer)(&data[0]), l)

	oid.C_gss_OID = C.gss_OID(s)
	oid.alloc = allocMalloc

	// because of the alignment issues I can't access o.oid's fields from go,
	// so invoking a C function to do the same as:
	// oid.C_gss_OID.length = l
	// oid.C_gss_OID.elements = c
	C.helper_gss_OID_desc_set_elements(oid.C_gss_OID, C.OM_uint32(l), e)

	return oid, nil
}
Beispiel #6
0
// Unwrap implements gss_unwrap API, as per https://tools.ietf.org/html/rfc2743#page-66.
// outputMessageBuffer must be .Release()-ed by the caller
func (ctx *CtxId) Unwrap(
	inputMessageBuffer *Buffer) (
	outputMessageBuffer *Buffer, confState bool, qopState QOP, err error) {

	min := C.OM_uint32(0)

	outputMessageBuffer, err = ctx.MakeBuffer(allocGSSAPI)
	if err != nil {
		return nil, false, 0, err
	}

	encrypted := C.int(0)
	qop := C.gss_qop_t(0)

	maj := C.wrap_gss_unwrap(ctx.Fp_gss_unwrap,
		&min,
		ctx.C_gss_ctx_id_t,
		inputMessageBuffer.C_gss_buffer_t,
		outputMessageBuffer.C_gss_buffer_t,
		&encrypted,
		&qop)

	err = ctx.stashLastStatus(maj, min)
	if err != nil {
		return nil, false, 0, err
	}

	return outputMessageBuffer,
		encrypted != 0,
		QOP(qop),
		nil
}
Beispiel #7
0
// InquireContext returns fields about a security context.
func (ctx *CtxId) InquireContext() (
	srcName *Name, targetName *Name, lifetimeRec time.Duration, mechType *OID,
	ctxFlags uint64, locallyInitiated bool, open bool, err error) {

	min := C.OM_uint32(0)
	srcName = ctx.NewName()
	targetName = ctx.NewName()
	rec := C.OM_uint32(0)
	mechType = ctx.NewOID()
	flags := C.OM_uint32(0)
	li := C.int(0)
	opn := C.int(0)

	maj := C.wrap_gss_inquire_context(ctx.Fp_gss_inquire_context,
		&min,
		ctx.C_gss_ctx_id_t,
		&srcName.C_gss_name_t,
		&targetName.C_gss_name_t,
		&rec,
		&mechType.C_gss_OID,
		&flags,
		&li,
		&opn)

	err = ctx.stashLastStatus(maj, min)
	if err != nil {
		ctx.Err("InquireContext: ", err)
		return nil, nil, 0, nil, 0, false, false, err
	}

	lifetimeRec = time.Duration(rec) * time.Second
	ctxFlags = uint64(flags)

	if li != 0 {
		locallyInitiated = true
	}
	if opn != 0 {
		open = true
	}

	return srcName, targetName, lifetimeRec, mechType, ctxFlags, locallyInitiated, open, nil
}
Beispiel #8
0
// Release frees a credential.
func (c *CredId) Release() error {
	if c == nil || c.C_gss_cred_id_t == nil {
		return nil
	}

	min := C.OM_uint32(0)
	maj := C.wrap_gss_release_cred(c.Fp_gss_release_cred,
		&min,
		&c.C_gss_cred_id_t)

	return c.stashLastStatus(maj, min)
}
Beispiel #9
0
// DeleteSecContext frees a security context.
// NB: I decided not to implement the outputToken parameter since its use is no
// longer recommended, and it would have to be Released by the caller
func (ctx *CtxId) DeleteSecContext() error {
	if ctx == nil || ctx.C_gss_ctx_id_t == nil {
		return nil
	}

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	min := C.OM_uint32(0)
	maj := C.wrap_gss_delete_sec_context(ctx.Fp_gss_delete_sec_context,
		&min, &ctx.C_gss_ctx_id_t, nil)

	return ctx.stashLastStatus(maj, min)
}
Beispiel #10
0
// AddCred implements gss_add_cred API, as per
// https://tools.ietf.org/html/rfc2743#page-36. outputCredHandle, actualMechs
// must be .Release()-ed by the caller
func (lib *Lib) AddCred(inputCredHandle *CredId,
	desiredName *Name, desiredMech *OID, credUsage CredUsage,
	initiatorTimeReq time.Duration, acceptorTimeReq time.Duration) (
	outputCredHandle *CredId, actualMechs *OIDSet,
	initiatorTimeRec time.Duration, acceptorTimeRec time.Duration,
	err error) {

	min := C.OM_uint32(0)
	actualMechs = lib.NewOIDSet()
	outputCredHandle = lib.NewCredId()
	initSeconds := C.OM_uint32(0)
	acceptSeconds := C.OM_uint32(0)

	maj := C.wrap_gss_add_cred(lib.Fp_gss_add_cred,
		&min,
		inputCredHandle.C_gss_cred_id_t,
		desiredName.C_gss_name_t,
		desiredMech.C_gss_OID,
		C.gss_cred_usage_t(credUsage),
		C.OM_uint32(initiatorTimeReq.Seconds()),
		C.OM_uint32(acceptorTimeReq.Seconds()),
		&outputCredHandle.C_gss_cred_id_t,
		&actualMechs.C_gss_OID_set,
		&initSeconds,
		&acceptSeconds)

	err = lib.stashLastStatus(maj, min)
	if err != nil {
		return nil, nil, 0, 0, err
	}

	return outputCredHandle,
		actualMechs,
		time.Duration(initSeconds) * time.Second,
		time.Duration(acceptSeconds) * time.Second,
		nil
}
Beispiel #11
0
// VerifyMIC implements gss_VerifyMIC API, as per https://tools.ietf.org/html/rfc2743#page-64.
func (ctx *CtxId) VerifyMIC(messageBuffer *Buffer, tokenBuffer *Buffer) (
	qopState QOP, err error) {

	min := C.OM_uint32(0)
	qop := C.gss_qop_t(0)

	maj := C.wrap_gss_verify_mic(ctx.Fp_gss_verify_mic,
		&min,
		ctx.C_gss_ctx_id_t,
		messageBuffer.C_gss_buffer_t,
		tokenBuffer.C_gss_buffer_t,
		&qop)

	err = ctx.stashLastStatus(maj, min)
	if err != nil {
		return 0, err
	}

	return QOP(qop), nil
}
Beispiel #12
0
// Wrap implements gss_wrap API, as per https://tools.ietf.org/html/rfc2743#page-65.
// outputMessageBuffer must be .Release()-ed by the caller
func (ctx *CtxId) Wrap(
	confReq bool, qopReq QOP, inputMessageBuffer *Buffer) (
	confState bool, outputMessageBuffer *Buffer, err error) {

	min := C.OM_uint32(0)

	encrypt := C.int(0)
	if confReq {
		encrypt = 1
	}

	outputMessageBuffer, err = ctx.MakeBuffer(allocGSSAPI)
	if err != nil {
		return false, nil, err
	}

	encrypted := C.int(0)

	maj := C.wrap_gss_wrap(ctx.Fp_gss_wrap,
		&min,
		ctx.C_gss_ctx_id_t,
		encrypt,
		C.gss_qop_t(qopReq),
		inputMessageBuffer.C_gss_buffer_t,
		&encrypted,
		outputMessageBuffer.C_gss_buffer_t)

	err = ctx.stashLastStatus(maj, min)
	if err != nil {
		return false, nil, err
	}

	return encrypted != 0,
		outputMessageBuffer,
		nil
}
Beispiel #13
0
// GetMIC implements gss_GetMIC API, as per https://tools.ietf.org/html/rfc2743#page-63.
// messageToken must be .Release()-ed by the caller.
func (ctx *CtxId) GetMIC(qopReq QOP, messageBuffer *Buffer) (
	messageToken *Buffer, err error) {

	min := C.OM_uint32(0)

	token, err := ctx.MakeBuffer(allocGSSAPI)
	if err != nil {
		return nil, err
	}

	maj := C.wrap_gss_get_mic(ctx.Fp_gss_get_mic,
		&min,
		ctx.C_gss_ctx_id_t,
		C.gss_qop_t(qopReq),
		messageBuffer.C_gss_buffer_t,
		token.C_gss_buffer_t)

	err = ctx.stashLastStatus(maj, min)
	if err != nil {
		return nil, err
	}

	return token, nil
}
Beispiel #14
0
// AcceptSecContext accepts an initialized security context. Usually called by
// the server. May return ErrContinueNeeded if the client is to make another
// iteration of exchanging token with the service
func (lib *Lib) AcceptSecContext(
	ctxIn *CtxId, acceptorCredHandle *CredId, inputToken *Buffer,
	inputChanBindings ChannelBindings) (
	ctxOut *CtxId, srcName *Name, actualMechType *OID, outputToken *Buffer,
	retFlags uint32, timeRec time.Duration, delegatedCredHandle *CredId,
	err error) {

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	// prepare the inputs
	C_acceptorCredHandle := C.gss_cred_id_t(nil)
	if acceptorCredHandle != nil {
		C_acceptorCredHandle = acceptorCredHandle.C_gss_cred_id_t
	}

	C_inputToken := C.gss_buffer_t(nil)
	if inputToken != nil {
		C_inputToken = inputToken.C_gss_buffer_t
	}

	// prepare the outputs
	if ctxIn != nil {
		ctxCopy := *ctxIn
		ctxOut = &ctxCopy
	} else {
		ctxOut = lib.GSS_C_NO_CONTEXT
	}

	min := C.OM_uint32(0)
	srcName = lib.NewName()
	actualMechType = lib.NewOID()
	outputToken, err = lib.MakeBuffer(allocGSSAPI)
	if err != nil {
		return nil, nil, nil, nil, 0, 0, nil, err
	}
	flags := C.OM_uint32(0)
	timerec := C.OM_uint32(0)
	delegatedCredHandle = lib.NewCredId()

	maj := C.wrap_gss_accept_sec_context(lib.Fp_gss_accept_sec_context,
		&min,
		&ctxOut.C_gss_ctx_id_t, // used as both in and out param
		C_acceptorCredHandle,
		C_inputToken,
		C.gss_channel_bindings_t(inputChanBindings),
		&srcName.C_gss_name_t,
		&actualMechType.C_gss_OID,
		outputToken.C_gss_buffer_t,
		&flags,
		&timerec,
		&delegatedCredHandle.C_gss_cred_id_t)

	err = lib.stashLastStatus(maj, min)
	if err != nil {
		lib.Err("AcceptSecContext: ", err)
		return nil, nil, nil, nil, 0, 0, nil, err
	}

	if MajorStatus(maj).ContinueNeeded() {
		err = ErrContinueNeeded
	}

	return ctxOut, srcName, actualMechType, outputToken, uint32(flags),
		time.Duration(timerec) * time.Second, delegatedCredHandle, err
}
Beispiel #15
0
// InitSecContext initiates a security context. Usually invoked by the client.
// A Context (CtxId) describes the state at one end of an authentication
// protocol. May return ErrContinueNeeded if the client is to make another
// iteration of exchanging token with the service
func (lib *Lib) InitSecContext(initiatorCredHandle *CredId, ctxIn *CtxId,
	targetName *Name, mechType *OID, reqFlags uint32, timeReq time.Duration,
	inputChanBindings ChannelBindings, inputToken *Buffer) (
	ctxOut *CtxId, actualMechType *OID, outputToken *Buffer, retFlags uint32,
	timeRec time.Duration, err error) {

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	// prepare the input params
	C_initiator := C.gss_cred_id_t(nil)
	if initiatorCredHandle != nil {
		C_initiator = initiatorCredHandle.C_gss_cred_id_t
	}

	C_mechType := C.gss_OID(nil)
	if mechType != nil {
		C_mechType = mechType.C_gss_OID
	}

	C_inputToken := C.gss_buffer_t(nil)
	if inputToken != nil {
		C_inputToken = inputToken.C_gss_buffer_t
	}

	// prepare the outputs.
	if ctxIn != nil {
		ctxCopy := *ctxIn
		ctxOut = &ctxCopy
	} else {
		ctxOut = lib.NewCtxId()
	}

	min := C.OM_uint32(0)
	actualMechType = lib.NewOID()
	outputToken, err = lib.MakeBuffer(allocGSSAPI)
	if err != nil {
		return nil, nil, nil, 0, 0, err
	}

	flags := C.OM_uint32(0)
	timerec := C.OM_uint32(0)

	maj := C.wrap_gss_init_sec_context(lib.Fp_gss_init_sec_context,
		&min,
		C_initiator,
		&ctxOut.C_gss_ctx_id_t, // used as both in and out param
		targetName.C_gss_name_t,
		C_mechType,
		C.OM_uint32(reqFlags),
		C.OM_uint32(timeReq.Seconds()),
		C.gss_channel_bindings_t(inputChanBindings),
		C_inputToken,
		&actualMechType.C_gss_OID,
		outputToken.C_gss_buffer_t,
		&flags,
		&timerec)

	err = lib.stashLastStatus(maj, min)
	if err != nil {
		return nil, nil, nil, 0, 0, err
	}

	if MajorStatus(maj).ContinueNeeded() {
		err = ErrContinueNeeded
	}

	return ctxOut, actualMechType, outputToken,
		uint32(flags), time.Duration(timerec) * time.Second,
		err
}