x500_dap_client

package module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 3, 2025 License: MIT Imports: 22 Imported by: 0

README

X.500 Directory Access Protocol (DAP) Client in Go

This is an implementation an X.500 Directory Access Protocol (DAP) client in Go as described in ITU-T Recommendation X.519. It currently only supports the use of the Internet Directly-Mapped (IDM) protocol also described in the same standard, but this library was implemented in such a way as to facilitate easy implementation of OSI transport later on, if desired.

This library was developed and tested against Meerkat DSA, which, to my knowledge, is one of two free and open source X.500 directories. If you are interested in working with X.500 directories, consider checking it out!

Usage

This library exposes multiple layers of complexity to the user, which are, in order of increasing abstraction:

  1. The Remote Operation Service Element (ROSE) Layer (implementing RemoteOperationServiceElement)
  2. The Directory Access Protocol (DAP) Layer (implementing DirectoryAccessClient)
  3. The Simple Directory Access Protocol Layer (implementing SimpleDirectoryAccessClient)
  4. The group management interface (implementing DirectoryGroupClient)

With increasing abstraction, you lose a little bit of control and possibly performance too. The simplest, more abstracted interface is designed for common use cases, like adding a single attribute to an entry named by a distinguished name, or checking if a person named by a distinguished name is a member of the group. If you need more specialized features, you may have to use the lower-level APIs.

You are likely to never need to use the ROSE API, but one interesting consequence of exposing this is that you could use a different programming language to parse and create the payloads for directory operations, and just use this Go library for handling the IDM and ROSE layers.

Binding

To use these APIs, the first thing you will need to do is bind to the directory server.

Anonymously
conn, err := net.Dial("tcp", "localhost:4632") // replace with your DSA address
if err != nil {
    return err
}
errchan := make(chan error)
idm := x500_dap_client.IDMClient(conn, &x500_dap_client.IDMClientConfig{
    StartTLSPolicy: x500_dap_client.StartTLSNever,
    Errchan:        errchan,
})
go func() {
    e := <-errchan
    fmt.Println(e)
}()
ctx, cancel := context.WithTimeout(context.Background(), sensibleTimeout)
defer cancel()
_, err = idm.BindAnonymously(ctx) // Yes, it is that simple!
if err != nil {
    return err
}
Simple Credentials (Username and Password)
conn, err := net.Dial("tcp", "localhost:4632") // replace with your DSA address
if err != nil {
    return err
}
idm := IDMClient(conn, &IDMClientConfig{
    StartTLSPolicy: StartTLSNever,
})
ctx, cancel := context.WithTimeout(context.Background(), sensibleTimeout)
defer cancel()
dn := getDN()
simpleCreds := x500.SimpleCredentials{
    Name: dn,
    Password: asn1.RawValue{
        Class:      asn1.ClassContextSpecific,
        Tag:        2,
        IsCompound: true,
        Bytes:      []byte{4, 4, 'a', 's', 'd', 'f'},
    },
}
credsEncoded, err := asn1.Marshal(simpleCreds)
if err != nil {
    t.Error(err)
    return
}
arg := X500AssociateArgument{
    V1: true,
    V2: true,
    Credentials: &asn1.RawValue{
        Class:      asn1.ClassContextSpecific,
        Tag:        0,
        IsCompound: true,
        Bytes:      credsEncoded,
    },
}
response, err := idm.Bind(ctx, arg)
if err != nil {
    t.Error(err.Error())
    return
}
if response.OutcomeType != OP_OUTCOME_RESULT {
    fmt.Printf("Authentication failure: outcome type %v\n", response.OutcomeType)
    return
}
Binding with Strong Authentication

Strong authentication is fairly simple: just configure a signing certificate and signing key, then invoke BindStrongly().

keyBlock, _ := pem.Decode([]byte(keyPem))
if keyBlock == nil || keyBlock.Type != "PRIVATE KEY" {
    return errors.New("Failed to decode PEM block containing the private key")
}

// Parse the certificate
privKey, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
if err != nil {
    return err
}

signer, is_signer := privKey.(crypto.Signer)
if !is_signer {
    return errors.New("not an signing key")
}

idm := x500_dap_client.IDMClient(conn, &x500_dap_client.IDMClientConfig{
    StartTLSPolicy: StartTLSNever,
    Errchan:        errchan,
    SigningCert: &x500.CertificationPath{
        UserCertificate:   *cert,
        TheCACertificates: make([]x500.CertificatePair, 0),
    },
    SigningKey: &signer,
})

dn := getDistinguishedNameOfTheDSA()
_, err = idm.BindStrongly(ctx, dn, dn, nil)
if err != nil {
    t.Error(err.Error())
    return
}
ROSE-Layer Interface

Example usage:

invokeId := idm.GetNextInvokeId()
dn := getDN()
name_bytes, err := asn1.Marshal(dn)
if err != nil {
    return err
}
name := asn1.RawValue{FullBytes: name_bytes}
arg_data := x500.ReadArgumentData{
    Object: asn1.RawValue{
        Tag:        0,
        Class:      asn1.ClassContextSpecific,
        IsCompound: true,
        Bytes:      name.FullBytes,
    },
}
arg_bytes, err := asn1.MarshalWithParams(arg_data, "set")
if err != nil {
    return err
}
iidBytes, err := asn1.Marshal(invokeId)
if err != nil {
    return err
}
req := X500Request{
    InvokeId: asn1.RawValue{
        FullBytes: iidBytes,
    },
    OpCode: asn1.RawValue{
        Tag:        asn1.TagInteger,
        Class:      asn1.ClassUniversal,
        IsCompound: false,
        Bytes:      []byte{0x01}, // Read operation
    },
    Argument: asn1.RawValue{FullBytes: arg_bytes},
}
ctx, cancel = context.WithTimeout(context.Background(), sensibleTimeout)
defer cancel()
outcome, err := idm.Request(ctx, req)
if err != nil {
    return err
}
result := x500.ReadResultData{}
rest, err := asn1.UnmarshalWithParams(outcome.Parameter.FullBytes, &result, "set")
if err != nil {
    return err
}
if len(rest) > 0 {
    return err
}
for _, info := range result.Entry.Information {
    // Print out the attributes, use them for access control decisions, etc.
}
Directory Access Protocol (DAP) Interface

The bare-bones read operation API:

dn := getDN()
name_bytes, err := asn1.Marshal(dn)
if err != nil {
    return err
}
name := asn1.RawValue{FullBytes: name_bytes}
arg_data := x500.ReadArgumentData{
    Object: asn1.RawValue{
        Tag:        0,
        Class:      asn1.ClassContextSpecific,
        IsCompound: true,
        Bytes:      name.FullBytes,
    },
    SecurityParameters: x500.SecurityParameters{
        Target:          idm.ResultsSigning,
        ErrorProtection: idm.ErrorSigning,
    },
}
ctx, cancel = context.WithTimeout(context.Background(), sensibleTimeout)
defer cancel()
_, res, err := idm.Read(ctx, arg_data)
if err != nil {
    return err
}
for _, info := range res.Entry.Information {
    // Print out the attributes, use them for access control decisions, etc.
}
Simple Directory Access Protocol Interface

Even simpler read operation API:

dn := getDN()
attrs := make([]asn1.ObjectIdentifier, 1)
attrs[0] = x500.Id_at_countryName
ctx, cancel = context.WithTimeout(context.Background(), sensibleTimeout)
defer cancel()
_, res, err := idm.ReadSimple(ctx, dn, attrs)
if err != nil {
    t.Error(err.Error())
    return
}
for _, info := range res.Entry.Information {
    // Print out the attributes, use them for access control decisions, etc.
}
Group Management

To check if a user is in a group:

member := getPersonDN()
adminsGroup := getGroupDN()
ctx, cancel = context.WithTimeout(context.Background(), sensibleTimeout)
defer cancel()
_, res, err := idm.GroupCheckMember(ctx, adminsGroup, member, nil)
if res != nil && res.Matched {
    // Access granted
}
Unbind
ctx, cancel = context.WithTimeout(context.Background(), sensibleTimeout)
req := x500_dap_client.X500UnbindRequest{}
defer cancel()
_, err = idm.Unbind(ctx, req)
if err != nil {
    return err
}
Socket Closure

To close the underlying TCP or TLS socket, or any other underlying protocol layers, simply call CloseTransport().

err := idm.CloseTransport()
TLS and StartTLS

Using TLS is straight-forward. Just create a TLS connection, then pass it in to IDMClient().

conn, err := tls.Dial("tcp", "localhost:44632", &tls.Config{
    InsecureSkipVerify: true,
})
if err != nil {
    return err
}
idm := x500_dap_client.IDMClient(conn, &IDMClientConfig{
    StartTLSPolicy: StartTLSNever,
    Errchan:        errchan,
})

By default, if TLS is not used, StartTLS will be demanded; the connection will fail with an error if StartTLS does not succeed. You MUST disable the StartTLS upgrade if you plan to connect over cleartext. You can do this by setting IDMClientConfig.StartTLSPolicy to either StartTLSNever (never perform StartTLS), or StartTLSPrefer (try StartTLS, but keep going if it fails).

If StartTLS is to be used, this will be done when you invoke .Bind() or one of the higher-level APIs that themselves perform a bind operation. This is the one thing you don't get control over in this library: I had to do it this way for annoying technical reasons.

Signing Requests

To produce signed requests, all you have to do is configure a signing key and certificate like so:

keyBlock, _ := pem.Decode([]byte(keyPem))
if keyBlock == nil || keyBlock.Type != "PRIVATE KEY" {
    return errors.New("Failed to decode PEM block containing the private key")
}

// Parse the certificate
privKey, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
if err != nil {
    return err
}

signer, is_signer := privKey.(crypto.Signer)
if !is_signer {
    return errors.New("not an signing key")
}

idm := x500_dap_client.IDMClient(conn, &x500_dap_client.IDMClientConfig{
    StartTLSPolicy: StartTLSNever,
    Errchan:        errchan,
    SigningCert: &x500.CertificationPath{
        UserCertificate:   *cert,
        TheCACertificates: make([]x500.CertificatePair, 0),
    },
    SigningKey: &signer,
})

Any requests generated will silently have signatures applied. Only Ed25519, ECDSA, and RSA signatures are supported, and all of them only use SHA-256. There is no support for customizing the hash algorithm right now. If you attempt to use a key that is designed for some other algorithm, I don't know what will happen, actually.

If an RSA key is supplied, the rSASSA-PSS algorithm will be used, because it is more secure than the old RSASSA-PKCS1-v1.5 algorithm. If this is a problem for you, let me know.

Signed Results and Errors

This library does not implement any verification of signed results or errors. You get the full payload back with most APIs and it is expected that you verify them.

Error Handling

This library tries to avoid doing any logging to the console; we don't want to circumvent the logging middleware you've chosen for your application. Instead, the IDM stack takes an error channel, which you can supply when creating the stack, and use that to handle errors however you see fit, like so:

errchan := make(chan error)
idm := x500_dap_client.IDMClient(conn, &x500_dap_client.IDMClientConfig{
    StartTLSPolicy: x500_dap_client.StartTLSNever,
    Errchan:        errchan,
})
go func() {
    e := <-errchan
    fmt.Println(e)
}()

Tests

The tests are a great way to see examples for usage.

Notes for Users

You will need to set priority in the service controls. Golang defaults enums to 0, even if you use the default:1 tag on a struct member.

The timeLimit field of the service controls is populated by the timeout specified with the Context object. If there is no such timeout specified either in the service controls, or in the context object, the request will not timeout unless configured to do so at the TCP or TLS layers. The sizeLimit and attributeSizeLimit fields get populated automatically with sensible defaults unless you supply your own values.

This library supports requesting an attribute certificate from the DSA per the private extension used by Meerkat DSA.

Known issues: https://github.com/golang/go/issues/27426 Any SEQUENCE OF SET type will fail to be unmarshalled.

Documentation

Overview

X.500 Directory Access Protocol (DAP) client

Index

Constants

View Source
const (
	CRIT_EXT_BIT_SUBENTRIES                            = 1
	CRIT_EXT_BIT_COPY_SHALL_DO                         = 2
	CRIT_EXT_BIT_ATTRIBUTE_SIZE_LIMIT                  = 3
	CRIT_EXT_BIT_EXTRA_ATTRIBUTES                      = 4
	CRIT_EXT_BIT_MODIFY_RIGHTS_REQUEST                 = 5
	CRIT_EXT_BIT_PAGED_RESULTS_REQUEST                 = 6
	CRIT_EXT_BIT_MATCHED_VALUES_ONLY                   = 7
	CRIT_EXT_BIT_EXTENDED_FILTER                       = 8
	CRIT_EXT_BIT_TARGET_SYSTEM                         = 9
	CRIT_EXT_BIT_USE_ALIAS_ON_UPDATE                   = 10
	CRIT_EXT_BIT_NEW_SUPERIOR                          = 11
	CRIT_EXT_BIT_MANAGE_DSA_IT                         = 12
	CRIT_EXT_BIT_USE_OF_CONTEXTS                       = 13
	CRIT_EXT_BIT_PARTIAL_NAME_RESOLUTION               = 14
	CRIT_EXT_BIT_OVERSPEC_FILTER                       = 15
	CRIT_EXT_BIT_SELECTION_ON_MODIFY                   = 16
	CRIT_EXT_BIT_SECURITY_OPERATION_CODE               = 18
	CRIT_EXT_BIT_SECURITY_ATTRIBUTE_CERTIFICATION_PATH = 19
	CRIT_EXT_BIT_SECURITY_ERROR_PROTECTION             = 20
	CRIT_EXT_BIT_SERVICE_ADMINISTRATION                = 25
	CRIT_EXT_BIT_ENTRY_COUNT                           = 26
	CRIT_EXT_BIT_HIERARCHY_SELECTIONS                  = 27
	CRIT_EXT_BIT_RELAXATION                            = 28
	CRIT_EXT_BIT_FAMILY_GROUPING                       = 29
	CRIT_EXT_BIT_FAMILY_RETURN                         = 30
	CRIT_EXT_BIT_DN_ATTRIBUTES                         = 31
	CRIT_EXT_BIT_FRIEND_ATTRIBUTES                     = 32
	CRIT_EXT_BIT_ABANDON_OF_PAGED_RESULTS              = 33
	CRIT_EXT_BIT_PAGED_RESULTS_ON_THE_DSP              = 34
	CRIT_EXT_BIT_REPLACE_VALUES                        = 35
)
View Source
const BIND_RESPONSE_RECEIVE_BUFFER_SIZE = 4096
View Source
const DEFAULT_MAX_FRAME = uint(10_000_000) // 10 megabytes
View Source
const DEFAULT_MAX_FRAMES = uint(10)
View Source
const DEFAULT_MAX_PDU = uint(10_000_000) // 10 megabytes
View Source
const NORMAL_ATTR_SIZE_LIMIT = 1_000_000
View Source
const NORMAL_SIZE_LIMIT = 100_000
View Source
const SIZE_OF_IDMV1_FRAME = uint32(6)
View Source
const SIZE_OF_IDMV2_FRAME = uint32(8)
View Source
const SMALL_ATTR_SIZE_LIMIT = 65535
View Source
const SMALL_SIZE_LIMIT = 10_000

Variables

View Source
var FULL_IDMV1_START_TLS_PDU = [...]byte{1, 1, 0, 0, 0, 4, 0xA9, 2, 5, 0}
View Source
var FULL_IDMV1_UNBIND_PDU = [...]byte{1, 1, 0, 0, 0, 4, 0xA7, 2, 5, 0}
View Source
var FULL_IDMV2_START_TLS_PDU = [...]byte{2, 1, 0, 0, 0, 0, 0, 4, 0xA9, 2, 5, 0}
View Source
var FULL_IDMV2_UNBIND_PDU = [...]byte{2, 1, 0, 0, 0, 0, 0, 4, 0xA7, 2, 5, 0}

Functions

func GetIdmFrame

func GetIdmFrame(payload []byte, version int) []byte

Produce IDM Frame header given a payload and version.

func HashAlgFromHash

func HashAlgFromHash(h crypto.Hash) (alg pkix.AlgorithmIdentifier, err error)

Types

type DN

type DirectoryAccessClient

type DirectoryAccessClient interface {
	RemoteOperationServiceElement

	// Perform the `read` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	Read(ctx context.Context, arg_data x500.ReadArgumentData) (response X500OpOutcome, result *x500.ReadResultData, err error)

	// Perform the `compare` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	Compare(ctx context.Context, arg_data x500.CompareArgumentData) (resp X500OpOutcome, result *x500.CompareResultData, err error)

	// Perform the `abandon` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	Abandon(ctx context.Context, arg_data x500.AbandonArgumentData) (resp X500OpOutcome, result *x500.AbandonResultData, err error)

	// Perform the `list` Directory Access Protocol (DAP) operation. The `info` returned may be `nil`.
	List(ctx context.Context, arg_data x500.ListArgumentData) (resp X500OpOutcome, info *x500.ListResultData_listInfo, err error)

	// Perform the `search` Directory Access Protocol (DAP) operation. The `info` returned may be `nil`.
	Search(ctx context.Context, arg_data x500.SearchArgumentData) (resp X500OpOutcome, info *x500.SearchResultData_searchInfo, err error)

	// Perform the `addEntry` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	AddEntry(ctx context.Context, arg_data x500.AddEntryArgumentData) (resp X500OpOutcome, result *x500.AddEntryResultData, err error)

	// Perform the `removeEntry` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	RemoveEntry(ctx context.Context, arg_data x500.RemoveEntryArgumentData) (resp X500OpOutcome, result *x500.RemoveEntryResultData, err error)

	// Perform the `modifyEntry` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	ModifyEntry(ctx context.Context, arg_data x500.ModifyEntryArgumentData) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Perform the `modifyDN` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	ModifyDN(ctx context.Context, arg_data x500.ModifyDNArgumentData) (resp X500OpOutcome, result *x500.ModifyDNResultData, err error)

	// Perform the `changePassword` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	ChangePassword(ctx context.Context, arg_data x500.ChangePasswordArgumentData) (resp X500OpOutcome, result *x500.ChangePasswordResultData, err error)

	// Perform the `administerPassword` Directory Access Protocol (DAP) operation. The `result` returned may be `nil`.
	AdministerPassword(ctx context.Context, arg_data x500.AdministerPasswordArgumentData) (resp X500OpOutcome, result *x500.AdministerPasswordResultData, err error)
}

X.500 Directory Access Protocol (DAP) Client

type DirectoryGroupClient added in v1.0.0

type DirectoryGroupClient interface {

	// Add a group member. If `uid` is `nil`, the `member` attribute is used,
	// otherwise, the `uniqueMember` attribute is used.
	GroupAdd(ctx context.Context, group, member DN, uid *asn1.BitString) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Remove a group member. If `uid` is `nil`, the `member` attribute is used,
	// otherwise, the `uniqueMember` attribute is used.
	GroupRemove(ctx context.Context, group, member DN, uid *asn1.BitString) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Check for the presence of a member in a group. If `uid` is `nil`, the
	// `member` attribute is used, otherwise, the `uniqueMember` attribute is used.
	GroupCheckMember(ctx context.Context, group, member DN, uid *asn1.BitString) (resp X500OpOutcome, result *x500.CompareResultData, err error)
}

Client for managing groups: X.500 directory entries of object class `groupOfNames` (`2.5.6.9`), `groupOfUniqueNames` (`2.5.6.17`), or any other object class that takes values of type `member` (`2.5.4.31`) or `uniqueMember` (`2.5.4.50`).

type IDMClientConfig

type IDMClientConfig struct {
	// Used to request result signing.
	// Set to ProtectionRequest_Signed if you want signed results.
	// Note that directories do not have to honor this request.
	ResultSigning x500.ProtectionRequest

	// Used to request error signing.
	// Set to ErrorProtectionRequest_Signed if you want signed errors.
	// Note that directories do not have to honor this request.
	ErrorSigning x500.ErrorProtectionRequest

	// TLS configuration used if performing StartTLS.
	TlsConfig *tls.Config

	// Request signing key
	SigningKey *crypto.Signer

	// Request signing certificate
	SigningCert *x500.CertificationPath

	// Policy towards StartTLS: Do you _require_ it, merely _prefer_ it, or
	// do not want it at all?
	//
	//   [StartTLSDemand]: If TLS is not already used, REQUIRE StartTLS to succeed,
	//                     returning an error if it does not. (The default.)
	//   [StartTLSPrefer]: If TLS is not already used, attempt StartTLS, but
	//                     continue to bind to the directory if that fails.
	//   [StartTLSNever]:  Do not attempt StartTLS.
	//
	StartTLSPolicy StartTLSChoice

	// Use Internet Directly-Mapped (IDM) Protocol version 1.
	// Version 2 is preferred by default, because we can request that the
	// directory return all data encoded using the Distinguished Encoding Rules
	// (DER), which is what Go, and hence this library, supports.
	// Future versions of this library may support BER, so this may become
	// obsolete. Still, there's virtually no reason to use version 1, except
	// saving two bytes per frame.
	UseIDMv1 bool

	// A channel where errors are sent. This library avoids doing any logging
	// to the console when there are errors. Instead, you pass in an error
	// channel, and you listen on that error channel for errors, which you can
	// then do whatever you want with (usually logging).
	// If you do not supply this, errors will be logged to the stderr console.
	Errchan chan error

	// Maximum IDM Frame Size. By default, 10 megabytes, which is huge, but
	// probably big enough to accomodate a large search result.
	MaxFrameSize uint

	// Maximum IDM PDU Size. By default, 10 megabytes, which is huge, but
	// probably big enough to accomodate a large search result.
	MaxPDUSize uint

	// Maximum IDM Frames per PDU. IDM PDUs can be split across frames.
	// This limit prevents malicious directories from supplying an infinitely
	// large number of IDM frames and exhausting your machine's memory or
	// requiring an outrageously computationally expensive concatenation of
	// multiple large frames in memory.
	// Set to 10 by default.
	MaxFramesPerPDU uint
}

Configuration to create an IDMProtocolStack.

type IDMFrame

type IDMFrame struct {
	Version  uint8
	Final    uint8
	Encoding uint16
	Data     []byte
}

type IDMProtocolStack

type IDMProtocolStack struct {

	// Request signing key
	SigningKey *crypto.Signer

	// Request signing certificate
	SigningCert *x500.CertificationPath

	// Used to request result signing.
	// Set to ProtectionRequest_Signed if you want signed results.
	// Note that directories do not have to honor this request.
	ResultsSigning x500.ProtectionRequest

	// Used to request error signing.
	// Set to ErrorProtectionRequest_Signed if you want signed errors.
	// Note that directories do not have to honor this request.
	ErrorSigning x500.ErrorProtectionRequest

	// TLS configuration used if performing StartTLS.
	TlsConfig *tls.Config

	// Policy towards StartTLS: Do you _require_ it, merely _prefer_ it, or
	// do not want it at all?
	//
	//   StartTLSDemand: If TLS is not already used, REQUIRE StartTLS to succeed,
	//                   returning an error if it does not. (The default.)
	//   StartTLSPrefer: If TLS is not already used, attempt StartTLS, but
	//                   continue to bind to the directory if that fails.
	//   StartTLSNever:  Do not attempt StartTLS.
	//
	StartTLSPolicy StartTLSChoice

	// Maximum IDM Frame Size. By default, 10 megabytes, which is huge, but
	// probably big enough to accomodate a large search result.
	MaxFrameSize uint

	// Maximum IDM PDU Size. By default, 10 megabytes, which is huge, but
	// probably big enough to accomodate a large search result.
	MaxPDUSize uint

	// Maximum IDM Frames per PDU. IDM PDUs can be split across frames.
	// This limit prevents malicious directories from supplying an infinitely
	// large number of IDM frames and exhausting your machine's memory or
	// requiring an outrageously computationally expensive concatenation of
	// multiple large frames in memory.
	// Set to 10 by default.
	MaxFramesPerPDU uint

	// A channel where errors are sent. This library avoids doing any logging
	// to the console when there are errors. Instead, you pass in an error
	// channel, and you listen on that error channel for errors, which you can
	// then do whatever you want with (usually logging).
	// If you do not supply this, errors will be logged to the stderr console.
	ErrorChannel chan error
	// contains filtered or unexported fields
}

Internet Directly-Mapped (IDM) Protocol Stack for providing the IDM services described in ITU-T Recommendation X.519 (2019). Only used for X.500 directories, as far as I know.

func IDMClient

func IDMClient(socket Socket, options *IDMClientConfig) *IDMProtocolStack

Create an IDMProtocolStack

func (*IDMProtocolStack) Abandon

func (stack *IDMProtocolStack) Abandon(ctx context.Context, arg_data x500.AbandonArgumentData) (resp X500OpOutcome, result *x500.AbandonResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) abandon operation.

func (*IDMProtocolStack) AbandonById

func (stack *IDMProtocolStack) AbandonById(ctx context.Context, invokeId int) (resp X500OpOutcome, result *x500.AbandonResultData, err error)

Simplified API for performing an X.500 Directory Access Protocol (DAP) abandon operation. It just takes an invocation ID.

func (*IDMProtocolStack) AddAttribute added in v1.0.0

func (stack *IDMProtocolStack) AddAttribute(ctx context.Context, dn DN, attr x500.Attribute) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

Add a new attribute to an entry, returning an X.500 attribute error if the attribute already exists.

func (*IDMProtocolStack) AddEntry

func (stack *IDMProtocolStack) AddEntry(ctx context.Context, arg_data x500.AddEntryArgumentData) (resp X500OpOutcome, result *x500.AddEntryResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) addEntry operation.

func (*IDMProtocolStack) AddEntrySimple

func (stack *IDMProtocolStack) AddEntrySimple(ctx context.Context, dn x500.DistinguishedName, attrs []x500.Attribute) (resp X500OpOutcome, result *x500.AddEntryResultData, err error)

Simplified API for performing an X.500 Directory Access Protocol (DAP) addEntry operation. It just takes an entry's distinguished name and its attributes. If you need to use the `targetSystem` parameter to create a new hierarchical operational binding (HOB), you will have to use [AddEntry] instead.

func (*IDMProtocolStack) AddValues added in v1.0.0

func (stack *IDMProtocolStack) AddValues(ctx context.Context, dn DN, values x500.Attribute) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

Add new values to an entry, creating the attribute if it does not exist. If the values already exist, a directory error is returned.

func (*IDMProtocolStack) AdministerPassword

func (stack *IDMProtocolStack) AdministerPassword(ctx context.Context, arg_data x500.AdministerPasswordArgumentData) (resp X500OpOutcome, result *x500.AdministerPasswordResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) administerPassword operation.

func (*IDMProtocolStack) AdministerPasswordSimple

func (stack *IDMProtocolStack) AdministerPasswordSimple(ctx context.Context, dn x500.DistinguishedName, new string) (resp X500OpOutcome, result *x500.AdministerPasswordResultData, err error)

Simplified API for performing an X.500 Directory Access Protocol (DAP) changePassword operation. It just takes an entry's distinguished name and its new password.

func (*IDMProtocolStack) AlterValues added in v1.0.0

func (stack *IDMProtocolStack) AlterValues(ctx context.Context, dn DN, attrtype x500.AttributeType, addend int) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

Add `addend` to the values of the attribute type. `addend` could be negative, which would result in subtraction.

func (*IDMProtocolStack) Bind

func (stack *IDMProtocolStack) Bind(ctx context.Context, arg X500AssociateArgument) (response X500AssociateOutcome, err error)

func (*IDMProtocolStack) BindAnonymously

func (stack *IDMProtocolStack) BindAnonymously(ctx context.Context) (response X500AssociateOutcome, err error)

func (*IDMProtocolStack) BindPlainly

func (stack *IDMProtocolStack) BindPlainly(ctx context.Context, username string, password string) (resp X500AssociateOutcome, err error)

Perform an X.500 Directory Access Protocol (DAP) bind operation using the PLAIN SASL method (which takes a username and password).

func (*IDMProtocolStack) BindSimply

func (stack *IDMProtocolStack) BindSimply(ctx context.Context, dn x500.DistinguishedName, password string) (resp X500AssociateOutcome, err error)

Perform an X.500 Directory Access Protocol (DAP) bind operation using simple authentication (the use of a distinguished name and a password).

func (*IDMProtocolStack) BindStrongly

func (stack *IDMProtocolStack) BindStrongly(ctx context.Context, requesterDN x500.DistinguishedName, recipientDN x500.DistinguishedName, acPath *x500.AttributeCertificationPath) (resp X500AssociateOutcome, err error)

Perform an X.500 Directory Access Protocol (DAP) bind operation using strong authentication (the use of cryptographic signatures / PKI to sign a verifiable token for the server).

func (*IDMProtocolStack) ChangePassword

func (stack *IDMProtocolStack) ChangePassword(ctx context.Context, arg_data x500.ChangePasswordArgumentData) (resp X500OpOutcome, result *x500.ChangePasswordResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) changePassword operation.

func (*IDMProtocolStack) ChangePasswordSimple

func (stack *IDMProtocolStack) ChangePasswordSimple(ctx context.Context, dn x500.DistinguishedName, old string, new string) (resp X500OpOutcome, result *x500.ChangePasswordResultData, err error)

Simplified API for performing an X.500 Directory Access Protocol (DAP) changePassword operation. It just takes an entry's distinguished name and its old and new passwords.

func (*IDMProtocolStack) CloseTransport

func (stack *IDMProtocolStack) CloseTransport() error

Close the underlying transport: in the case of IDM, the underlying TCP or TLS socket.

func (*IDMProtocolStack) Compare

func (stack *IDMProtocolStack) Compare(ctx context.Context, arg_data x500.CompareArgumentData) (resp X500OpOutcome, result *x500.CompareResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) compare operation.

func (*IDMProtocolStack) CompareSimple added in v1.0.0

func (stack *IDMProtocolStack) CompareSimple(ctx context.Context, dn DN, ava x500.AttributeValueAssertion) (resp X500OpOutcome, result *x500.CompareResultData, err error)

Simplified API for performing an X.500 Directory Access Protocol (DAP) compare operation. It just takes an entry name and an assertion.

func (*IDMProtocolStack) GetNextInvokeId

func (stack *IDMProtocolStack) GetNextInvokeId() int

Get the Next Invoke ID

func (*IDMProtocolStack) GroupAdd added in v1.0.0

func (stack *IDMProtocolStack) GroupAdd(ctx context.Context, group, member DN, uid *asn1.BitString) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

If uid is not nil, the uniqueMember attribute will be used. Otherwise, the member attribute will be used.

func (*IDMProtocolStack) GroupCheckMember added in v1.0.0

func (stack *IDMProtocolStack) GroupCheckMember(ctx context.Context, group, member DN, uid *asn1.BitString) (resp X500OpOutcome, result *x500.CompareResultData, err error)

If uid is not nil, the uniqueMember attribute will be used. Otherwise, the member attribute will be used.

func (*IDMProtocolStack) GroupRemove added in v1.0.0

func (stack *IDMProtocolStack) GroupRemove(ctx context.Context, group, member DN, uid *asn1.BitString) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

If uid is not nil, the uniqueMember attribute will be used. Otherwise, the member attribute will be used.

func (*IDMProtocolStack) List

Perform an X.500 Directory Access Protocol (DAP) list operation.

func (*IDMProtocolStack) ListByDN

func (stack *IDMProtocolStack) ListByDN(ctx context.Context, dn x500.DistinguishedName, limit int) (resp X500OpOutcome, info *x500.ListResultData_listInfo, err error)

Simplified API for performing an X.500 Directory Access Protocol (DAP) list operation. It just takes an entry's distinguished name and a limit of entries to return beneath it. `limit` will be unset if it is 0.

func (*IDMProtocolStack) ModifyDN

func (stack *IDMProtocolStack) ModifyDN(ctx context.Context, arg_data x500.ModifyDNArgumentData) (resp X500OpOutcome, result *x500.ModifyDNResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) modifyDN operation.

func (*IDMProtocolStack) ModifyEntry

func (stack *IDMProtocolStack) ModifyEntry(ctx context.Context, arg_data x500.ModifyEntryArgumentData) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) modifyEntry operation.

func (*IDMProtocolStack) Read

func (stack *IDMProtocolStack) Read(ctx context.Context, arg_data x500.ReadArgumentData) (response X500OpOutcome, result *x500.ReadResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) read operation.

func (*IDMProtocolStack) ReadSimple

func (stack *IDMProtocolStack) ReadSimple(ctx context.Context, dn x500.DistinguishedName, userAttributes []asn1.ObjectIdentifier) (response X500OpOutcome, result *x500.ReadResultData, err error)

Simplified API for performing an X.500 Directory Access Protocol (DAP) read operation when the target entry is targeted by its distinguished name (DN) and when you only need to query user attributes. If len(userAttributes) == 0, all user attributes will be selected.

If you need to request modify rights, you'll need to use the [Read] function.

func (*IDMProtocolStack) RemoveAttribute added in v1.0.0

func (stack *IDMProtocolStack) RemoveAttribute(ctx context.Context, dn DN, attr x500.AttributeType) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

Remove an attribute from an entry entirely, returning an X.500 attribute error if the attribute does not exist.

func (*IDMProtocolStack) RemoveEntry

func (stack *IDMProtocolStack) RemoveEntry(ctx context.Context, arg_data x500.RemoveEntryArgumentData) (resp X500OpOutcome, result *x500.RemoveEntryResultData, err error)

Perform an X.500 Directory Access Protocol (DAP) removeEntry operation.

func (*IDMProtocolStack) RemoveEntryByDN

func (stack *IDMProtocolStack) RemoveEntryByDN(ctx context.Context, dn x500.DistinguishedName) (resp X500OpOutcome, result *x500.RemoveEntryResultData, err error)

Simplified API for performing an X.500 Directory Access Protocol (DAP) removeEntry operation. It just takes an entry's distinguished name.

func (*IDMProtocolStack) RemoveValues added in v1.0.0

func (stack *IDMProtocolStack) RemoveValues(ctx context.Context, dn DN, values x500.Attribute) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

Remove values from an entry, returning an error if one or more do not exist. If the last value is removed, the whole attribute is removed.

func (*IDMProtocolStack) ReplaceValues added in v1.0.0

func (stack *IDMProtocolStack) ReplaceValues(ctx context.Context, dn DN, attr x500.Attribute) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

Replace an attribute entirely. If the supplied attribute is empty, the existing attribute is deleted, if it exists, but no error is returned if it does not.

func (*IDMProtocolStack) Request

func (stack *IDMProtocolStack) Request(ctx context.Context, req X500Request) (response X500OpOutcome, err error)

func (*IDMProtocolStack) ResetValue added in v1.0.0

func (stack *IDMProtocolStack) ResetValue(ctx context.Context, dn DN, attr x500.AttributeType) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

Remove all values that have contexts for which fallback is FALSE.

func (*IDMProtocolStack) Search

Perform an X.500 Directory Access Protocol (DAP) search operation.

func (*IDMProtocolStack) Unbind

func (stack *IDMProtocolStack) Unbind(_ context.Context, req X500UnbindRequest) (response X500UnbindOutcome, err error)

type OutcomeType

type OutcomeType = int
const (
	OP_OUTCOME_FAILURE OutcomeType = 0
	OP_OUTCOME_RESULT  OutcomeType = 1
	OP_OUTCOME_ERROR   OutcomeType = 2
	OP_OUTCOME_REJECT  OutcomeType = 3
	OP_OUTCOME_ABORT   OutcomeType = 4
)

type RejectProblem

type RejectProblem = asn1.Enumerated
const (
	REJECT_PROBLEM_UNRECOGNIZED_PDU               RejectProblem = 0
	REJECT_PROBLEM_MISTYPED_PDU                   RejectProblem = 1
	REJECT_PROBLEM_BADLY_STRUCTURED_PDU           RejectProblem = 2
	REJECT_PROBLEM_DUPLICATE_INVOCATION           RejectProblem = 10
	REJECT_PROBLEM_UNRECOGNIZED_OPERATION         RejectProblem = 11
	REJECT_PROBLEM_MISTYPED_ARGUMENT              RejectProblem = 12
	REJECT_PROBLEM_RESOURCE_LIMITATION            RejectProblem = 13
	REJECT_PROBLEM_RELEASE_IN_PROGRESS            RejectProblem = 14
	REJECT_PROBLEM_UNRECOGNIZED_INVOCATION_RESULT RejectProblem = 20
	REJECT_PROBLEM_RESULT_RESPONSE_UNEXPECTED     RejectProblem = 21
	REJECT_PROBLEM_MISTYPED_RESULT                RejectProblem = 22
	REJECT_PROBLEM_UNRECOGNIZED_INVOCATION_ERROR  RejectProblem = 30
	REJECT_PROBLEM_ERROR_RESPONSE_UNEXPECTED      RejectProblem = 31
	REJECT_PROBLEM_UNRECOGNIZED_ERROR             RejectProblem = 32
	REJECT_PROBLEM_UNEXPECTED_ERROR               RejectProblem = 33
	REJECT_PROBLEM_MISTYPED_PARAMETER             RejectProblem = 34
)

type RemoteOperationServiceElement

type RemoteOperationServiceElement interface {

	// Perform the Remote Operation Service Element (ROSE) Bind operation
	Bind(ctx context.Context, arg X500AssociateArgument) (response X500AssociateOutcome, err error)

	// Issue a Remote Operation Service Element (ROSE) request
	Request(ctx context.Context, req X500Request) (response X500OpOutcome, err error)

	// Unbind via the Remote Operation Service Element (ROSE)
	Unbind(ctx context.Context, req X500UnbindRequest) (response X500UnbindOutcome, err error)

	// Close the network layers / transport layers that facilitate the
	// Remote Operation Service Element (ROSE), such as by closing a TCP socket.
	// This is a separate operation from unbinding so that the underlying
	// transport may be re-used for a new session.
	CloseTransport() (err error)
}

Remote Operation Service Element (ROSE) per ITU-T Recommendation X.880.

For now, this is only implemented via the Internet Directly-Mapped (IDM) protocol defined in [ITU-T Recommendation X.519 (2019)](https://www.itu.int/itu-t/recommendations/rec.aspx?rec=X.519), but in the future, this may be implemented via [ISO Transport over TCP (ITOT)](https://www.rfc-editor.org/rfc/rfc1006), [Lightweight Presentation Protocol](https://www.rfc-editor.org/rfc/rfc1085), [DIXIE](https://www.rfc-editor.org/rfc/rfc1249), and others.

type SimpleDirectoryAccessClient added in v1.0.0

type SimpleDirectoryAccessClient interface {
	DirectoryAccessClient

	// Bind using simple authentication: your distinguished name and password
	BindSimply(ctx context.Context, dn DN, password string) (resp X500AssociateOutcome, err error)

	// Bind by signing a token with your configured signing key.
	// An error will be returned if no signing key or no signing cert is configured.
	// The `requesterDN` is _your_ DN. The `recipientDN` is the application entity
	// title of the DSA.
	BindStrongly(ctx context.Context, requesterdn DN, recipientdn DN, acPath *x500.AttributeCertificationPath) (resp X500AssociateOutcome, err error)

	// Bind using the `PLAIN` Simple Authentication and Security Layer (SASL) Mechanism
	BindPlainly(ctx context.Context, username string, password string) (resp X500AssociateOutcome, err error)

	// Read selected user attributes from an entry named by a distinguished name.
	// `result` may be `nil`
	ReadSimple(ctx context.Context, dn DN, userAttributes []asn1.ObjectIdentifier) (response X500OpOutcome, result *x500.ReadResultData, err error)

	// Remove an entry named by the distinguished name `dn` using the
	// `removeEntry` X.500 Directory Access Protocol (DAP) operation.
	RemoveEntryByDN(ctx context.Context, dn DN) (resp X500OpOutcome, result *x500.RemoveEntryResultData, err error)

	// Abandon an X.500 Directory operation by its invoke ID.
	AbandonById(ctx context.Context, invokeId int) (resp X500OpOutcome, result *x500.AbandonResultData, err error)

	// List up to `limit` subordinates underneath the entry named by the
	// distinguished name `dn`.
	ListByDN(ctx context.Context, dn DN, limit int) (resp X500OpOutcome, info *x500.ListResultData_listInfo, err error)

	// Add a new entry having distinguished name `dn` and composed of attributes
	// `attrs`. If you need to use the `targetSystem` field to add an entry in
	// another DSA and establish a hierarchical operational binding, you will
	// need to use the lower-level [AddEntry] method.
	AddEntrySimple(ctx context.Context, dn DN, attrs []x500.Attribute) (resp X500OpOutcome, result *x500.AddEntryResultData, err error)

	CompareSimple(ctx context.Context, dn DN, ava x500.AttributeValueAssertion) (resp X500OpOutcome, result *x500.CompareResultData, err error)

	// Invoke the `changePassword` operation on the entry named by distinguished
	// name `dn` using unencrypted values `old` and `new` for `oldPwd` and
	// `newPwd` respectively.
	ChangePasswordSimple(ctx context.Context, dn DN, old string, new string) (resp X500OpOutcome, result *x500.ChangePasswordResultData, err error)

	// Invoke the `administerPassword` operation on the entry named by
	// distinguished name `dn` using the unencrypted value `new` for `newPwd`.
	AdministerPasswordSimple(ctx context.Context, dn DN, new string) (resp X500OpOutcome, result *x500.AdministerPasswordResultData, err error)

	// Add a new attribute to an entry, returning an X.500 attribute error if
	// the attribute already exists.
	AddAttribute(ctx context.Context, dn DN, attr x500.Attribute) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Remove an attribute from an entry entirely, returning an X.500 attribute
	// error if the attribute does not exist.
	RemoveAttribute(ctx context.Context, dn DN, attr x500.AttributeType) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Add new values to an entry, creating the attribute if it does not exist.
	// If the values already exist, a directory error is returned.
	AddValues(ctx context.Context, dn DN, values x500.Attribute) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Remove values from an entry, returning an error if one or more do not
	// exist. If the last value is removed, the whole attribute is removed.
	RemoveValues(ctx context.Context, dn DN, values x500.Attribute) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Add `addend` to the values of the attribute type. `addend` could be
	// negative, which would result in subtraction.
	AlterValues(ctx context.Context, dn DN, attrtype x500.AttributeType, addend int) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Remove all values that have contexts for which fallback is FALSE.
	ResetValue(ctx context.Context, dn DN, attr x500.AttributeType) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)

	// Replace an attribute entirely. If the supplied attribute is empty, the
	// existing attribute is deleted, if it exists, but no error is returned if
	// it does not.
	ReplaceValues(ctx context.Context, dn DN, attr x500.Attribute) (resp X500OpOutcome, result *x500.ModifyEntryResultData, err error)
}

X.500 Directory Access Protocol (DAP) Client with convenience functions that provide a simpler interface.

type Socket

type Socket interface {
	io.Reader
	io.Writer
	Close() error
}

Socket defines a type that works with both TCP and TLS connections

type StartTLSChoice

type StartTLSChoice int
const (
	// Demand StartTLS: if TLS cannot be started, return an error.
	StartTLSDemand StartTLSChoice = iota
	// Try to start TLS. If it cannot be started, just continue without it.
	StartTLSPrefer StartTLSChoice = iota
	// Never attempt to start TLS.
	StartTLSNever StartTLSChoice = iota
)

type StartTLSOutcome

type StartTLSOutcome struct {
	// contains filtered or unexported fields
}

An Internet Directly-Mapped `startTLS` message outcome, which may be a `tlsResponse` message or an error.

type X500Abort

type X500Abort struct {
	PresentationContextIdentifierList x500.Presentation_context_identifier_list
	PresentationContextIdentifier     x500.Presentation_context_identifier
	AbortSource                       x500.ABRT_source
	ProviderReason                    x500.Abort_reason
	EventIdentifier                   x500.Event_identifier
	UserReason                        x500.Abort // Only used by IDM Abort
}

A Remote Operation Service Element (ROSE) abort

type X500AssociateArgument

type X500AssociateArgument struct {
	// OSI Protocol Fields
	ModeSelector                      int // SHOULD always be 1
	OSIProtocolVersion1               bool
	CallingPresentationSelector       []byte
	CalledPresentationSelector        []byte
	PresentationContextDefinitionList x500.Context_list
	TransferSyntaxName                asn1.ObjectIdentifier
	PresentationContextIdentifier     int

	// AARQ-apdu Fields
	ACSEProtocolVersion1          bool
	ApplicationContext            asn1.ObjectIdentifier
	CalledAPTitle                 x500.DistinguishedName
	CalledAETitle                 x500.GeneralName
	CalledAPInvocationIdentifier  x500.AP_invocation_identifier
	CalledAEInvocationIdentifier  x500.AE_invocation_identifier
	CallingAPTitle                x500.DistinguishedName
	CallingAETitle                x500.GeneralName
	CallingAPInvocationIdentifier x500.AP_invocation_identifier
	CallingAEInvocationIdentifier x500.AE_invocation_identifier
	ImplementationInformation     string

	// Fields from DirectoryBindArgument
	V1          bool
	V2          bool
	Credentials *x500.Credentials
}

The parameters of an X.500 directory bind, as well as those of the underlying Remote Operation Service Element (ROSE) and Association Control Service Element (ACSE), which are unused if not applicable to the underlying operation transport.

type X500AssociateOutcome

type X500AssociateOutcome struct {
	OutcomeType OutcomeType

	Parameter asn1.RawValue // Only set if OutcomeType != OPERATION_OUTCOME_TYPE_ABORT
	Abort     X500Abort     // Only set if OutcomeType == OPERATION_OUTCOME_TYPE_ABORT

	// OSI Protocol Fields
	ModeSelector                      int // SHOULD always be 1
	OSIProtocolVersion1               bool
	RespondingPresentationSelector    *big.Int
	PresentationContextDefinitionList x500.Result_list
	TransferSyntaxName                asn1.ObjectIdentifier
	PresentationContextIdentifier     int
	ProviderReason                    x500.Provider_reason

	// ACSE AARE-apdu and AAREerr-apdu Fields
	ACSEProtocolVersion1              bool
	ApplicationContext                asn1.ObjectIdentifier
	ACSEResult                        x500.Associate_result                                  // 0 if successful
	AssociateSourceDiagnosticUser     x500.Associate_source_diagnostic_acse_service_user     // Set to -1 if unset
	AssociateSourceDiagnosticProvider x500.Associate_source_diagnostic_acse_service_provider // Set to -1 if unset

	// ACSE uses separate responding AP-title and AE-qualifier fields, because
	// it is assumed that every AE has a directory name.
	// IDM uses GeneralName. Since a GeneralName is a superset, we use that
	// instead.
	RespondingAPTitle                x500.DistinguishedName
	RespondingAETitle                x500.GeneralName
	RespondingAPInvocationIdentifier int
	RespondingAEInvocationIdentifier int
	ImplementationInformation        string

	// Fields specific to the IDM protocol
	AETitleError x500.IdmBindError_aETitleError // Set to -1 if unset

	// Fields from DirectoryBindResult, directoryBindError
	V1                         bool
	V2                         bool
	Credentials                x500.Credentials     // NULL value if unset
	PwdResponseTimeLeft        int                  // -1 if unset
	PwdResponseGracesRemaining int                  // -1 if unset
	PwdResponseError           int                  // -1 if unset
	ServiceError               x500.ServiceProblem  // Set to -1 if unset
	SecurityError              x500.SecurityProblem // Set to -1 if unset
	SecurityParameters         x500.SecurityParameters
	// contains filtered or unexported fields
}

Describes the result of a directory bind, using either IDM or OSI protocols, and covering both bind success (result), bind error, and abort. (Reject is not a valid outcome for a bind operation.) To determine success, just check that OutcomeType == OPERATION_OUTCOME_TYPE_RESULT.

type X500OpOutcome

type X500OpOutcome struct {
	OutcomeType   OutcomeType
	InvokeId      x500.InvokeId // This is always set for any outcome type.
	OpCode        x500.Code     // Only set if OutcomeType == OPERATION_OUTCOME_TYPE_RESULT
	ErrCode       x500.Code     // Only set if OutcomeType == OPERATION_OUTCOME_TYPE_ERROR
	Parameter     asn1.RawValue // The result or error.
	RejectProblem RejectProblem // Only set if OutcomeType == OPERATION_OUTCOME_TYPE_REJECT
	Abort         X500Abort     // Only set if OutcomeType == OPERATION_OUTCOME_TYPE_ABORT
	// contains filtered or unexported fields
}

A Remote Operation Service Element (ROSE) outcome: a generalization over results, errors, rejections, aborts, etc. In other words, a union of all possible outcomes to a ROSE operation other than a failure happening at the lower layers, such as a TCP socket closure.

type X500Request

type X500Request struct {
	PresentationContextIdentifier x500.Presentation_context_identifier
	InvokeId                      x500.InvokeId
	OpCode                        x500.Code
	Argument                      asn1.RawValue
}

A Remote Operation Service Element (ROSE) request

type X500UnbindOutcome

type X500UnbindOutcome struct {
	PresentationContextIdentifier x500.Presentation_context_identifier
	Reason                        x500.Release_response_reason
}

A Remote Operation Service Element (ROSE) unbind outcome

type X500UnbindRequest

type X500UnbindRequest struct {
	PresentationContextIdentifier x500.Presentation_context_identifier
	Reason                        x500.Release_request_reason
}

A Remote Operation Service Element (ROSE) unbind request

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL