oiwAlgorithm OBJECT IDENTIFIER ::= {dssig 2}
oiwEncryptionAlgorithm OBJECT IDENTIFIER ::= {oiwAlgorithm 1}
oiwHashAlgorithm OBJECT IDENTIFIER ::= {oiwAlgorithm 2}
oiwSignatureAlgorithm OBJECT IDENTIFIER ::= {oiwAlgorithm 3}
oiwMD2 OBJECT IDENTIFIER ::= {oiwHashAlgorithm 1}
--null parameter
oiwMD2withRSA OBJECT IDENTIFIER ::= {oiwSignatureAlgorithm 1}
--null parameter
--X.501 definitions
AttributeType ::= OBJECT IDENTIFIER
AttributeValue ::= ANY
AttributeValueAssertion ::= SEQUENCE {AttributeType,AttributeValue}
Name ::= CHOICE { --only one for now
RDNSequence
}
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
DistinguishedName ::= RDNSequence
RelativeDistinguishedName ::= SET OF AttributeValueAssertion
--X.509 definitions (with proposed 1992 extensions presumed)
ENCRYPTED MACRO ::=
BEGIN
TYPE NOTATION ::= type(ToBeEnciphered)
VALUE NOTATION ::= value(VALUE BIT STRING)
END -- of ENCRYPTED
SIGNED MACRO ::=
BEGIN
TYPE NOTATION ::= type (ToBeSigned)
VALUE NOTATION ::= value (VALUE
SEQUENCE{
ToBeSigned,
AlgorithmIdentifier, --of the algorithm used to
--generate the signature
ENCRYPTED OCTET STRING --where the octet string is the
--result of the hashing of the
--value of "ToBeSigned"
}
)
END -- of SIGNED
SIGNATURE MACRO ::=
BEGIN
TYPE NOTATION ::= type (OfSignature)
VALUE NOTATION ::= value (VALUE
SEQUENCE {
AlgorithmIdentifier, --of the algorithm used to compute
ENCRYPTED OCTET STRING -- the signature where the octet
-- string is a function (e.g., a
-- compressed or hashed version)
-- of the value 'OfSignature',
-- which may include the
-- identifier of the algorithm
-- used to compute the signature
}
)
END -- of SIGNATURE
Certificate ::= SIGNED SEQUENCE {
version [0] Version DEFAULT v1988,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
valid Validity,
subject Name,
subjectPublicKey SubjectPublicKeyInfo,
issuerUID [1] IMPLICIT UID OPTIONAL, -- v1992
subjectUID [2] IMPLICIT UID OPTIONAL -- v1992
}
--The Algorithm Identifier for both the signature field
--and in the signature itself is:
-- oiwMD2withRSA (1.3.14.7.2.3.1)
Version ::= INTEGER {v1988(0), v1992(1)}
CertificateSerialNumber ::= INTEGER
Validity ::= SEQUENCE {
NotBefore UTCTime,
NotAfter UTCTime
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameter ANY DEFINED BY algorithm OPTIONAL
}
--The algorithms we support in one context or another are:
--oiwMD2withRSA (1.3.14.7.2.3.1) with parameter NULL
--rsa (2.5.8.1.1) with parameter keysize INTEGER which is
-- the keysize in bits
--decDEA (1.3.12.1001.7.1.2) with optional parameter
-- missing
--decDEAMAC (1.3.12.2.1011.7.3.3) with optional parameter
-- missing
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier, -- rsa (2.5.8.1.1)
subjectPublicKey BIT STRING
-- the "bits" further decode into a DASS public key
}
UID ::= BIT STRING
-- the following definitions are for Digital specified Algorithms
cryptoAlgorithm OBJECT IDENTIFIER ::= {digital 7}
decEncryptionAlgorithm OBJECT IDENTIFIER ::= {cryptoAlgorithm 1}
decHashAlgorithm OBJECT IDENTIFIER ::= {cryptoAlgorithm 2}
decSignatureAlgorithm OBJECT IDENTIFIER ::= {cryptoAlgorithm 3}
decDASSLessness OBJECT IDENTIFIER ::= {cryptoAlgorithm 6}
decMD2withRSA OBJECT IDENTIFIER ::= {decSignatureAlgorithm 1}
decMD4withRSA OBJECT IDENTIFIER ::= {decSignatureAlgorithm 2}
decDEAMAC OBJECT IDENTIFIER ::= {decSignatureAlgorithm 3}
decDEA OBJECT IDENTIFIER ::= {decEncryptionAlgorithm 2}
decMD2 OBJECT IDENTIFIER ::= {decHashAlgorithm 1}
decMD4 OBJECT IDENTIFIER ::= {decHashAlgorithm 2}
ShortPosixTime ::= INTEGER -- number of seconds since base time
LongPosixTime ::= SEQUENCE {
INTEGER, -- number of seconds since base time
INTEGER -- number of nanoseconds since second
}
ShortPosixValidity ::= SEQUENCE {
notBefore ShortPosixTime,
notAfter ShortPosixTime }
-- Note: Annex C of X.509 prescribes the following format for the
-- representation of a public key, but does not give the structure
-- a name.
DASSPublicKey ::= SEQUENCE {
modulus INTEGER,
exponent INTEGER
}
DASSPrivateKey ::= SEQUENCE {
p INTEGER , -- prime p
q [0] IMPLICIT INTEGER OPTIONAL , -- prime q
mod[1] IMPLICIT INTEGER OPTIONAL, -- modulus
exp [2] IMPLICIT INTEGER OPTIONAL, -- public exponent
dp [3] IMPLICIT INTEGER OPTIONAL , -- exponent mod p
dq [4] IMPLICIT INTEGER OPTIONAL , -- exponent mod q
cr [5] IMPLICIT INTEGER OPTIONAL , -- Chinese
--remainder coefficient
uid[6] IMPLICIT UID OPTIONAL,
more[7] IMPLICIT BIT STRING OPTIONAL --Reserved for
--future use
}
LocalUserName ::= OCTET STRING
ChannelId ::= OCTET STRING
VersionNumber ::= OCTET STRING (SIZE(3))
-- first octet is major version
-- second octet is minor version
-- third octet is ECO rev.
versionZero VersionNumber ::= '000000'H
Authenticator ::= SIGNED SEQUENCE {
type BIT STRING,
-- first bit `delegation required'
-- second bit `Mutual Authentication Requested'
whenSigned LongPosixTime ,
channelId [3] IMPLICIT ChannelId OPTIONAL
-- channel bindings are included when doing the
-- signature, but excluded when transmitting the
-- Authenticator
}
-- uses decDEAMAC (1.3.12.2.1011.7.3.3)
EncryptedKey ::= SEQUENCE {
algorithm AlgorithmIdentifier,
-- uses rsa (2.5.8.1.1)
encryptedAuthKey BIT STRING
-- as defined in section 4.4.5
}
SignatureOnEncryptedKey ::= SIGNATURE EncryptedKey
-- uses oiwMD2withRSA (1.3.14.7.2.3.1)
-- Signature bits computed over EncryptedKey structure
LoginTicket ::= SIGNED SEQUENCE {
version [0] IMPLICIT VersionNumber DEFAULT versionZero,
validity ShortPosixValidity ,
subjectUID UID ,
delegatingPublicKey SubjectPublicKeyInfo
}
-- uses oiwMD2withRSA (1.3.14.7.2.3.1)
Delegator ::= SEQUENCE {
algorithm AlgorithmIdentifier
-- decDEA encryption (1.3.12.1001.7.1.2)
encryptedPrivKey ENCRYPTED DASSPrivateKey,
-- (only p is included)
}
UserClaimant ::= SEQUENCE {
userTicket [0] IMPLICIT LoginTicket,
evidence CHOICE {
delegator [1] IMPLICIT Delegator ,
-- encrypted delegation private key
-- under DES authenticating key
-- present if delegating
sharedKeyTicketSignature [2]
IMPLICIT SignatureOnEncryptedKey
-- present if not delegating
} ,
userName [3] IMPLICIT Name OPTIONAL
-- name of user principal
}
EncryptedKeyandUserName ::= SEQUENCE {
encryptedKey EncryptedKey ,
username LocalUserName
}
SignatureOnEncryptedKeyandUserName ::=
SIGNATURE EncryptedKeyandUserName
-- uses oiwMD2withRSA (1.3.14.7.2.3.1)
-- Signature bits computed over
-- EncryptedKeyandUserName structure
-- using node private key
}
NodeClaimant ::= SEQUENCE {
nodeTicket Signature[0] IMPLICIT
SignatureOnEncryptedKeyandUserName,
nodeName [1] IMPLICIT Name OPTIONAL,
username [2] IMPLICIT LocalUserName OPTIONAL
}
AuthenticationToken ::= SEQUENCE {
version [0] IMPLICIT VersionNumber DEFAULT versionZero,
authenticator [1] IMPLICIT Authenticator ,
encryptedKey [2] IMPLICIT EncryptedKey OPTIONAL ,
-- required if initiating token
userclaimant [3] IMPLICIT UserClaimant OPTIONAL ,
-- missing if only doing node authentication
-- required if not doing node authentication
nodeclaimant [4] IMPLICIT NodeClaimant OPTIONAL
-- missing if only doing principal authentication
-- required if not doing principal authentication
}
MutualAuthenticationToken ::= CHOICE {
v1Response [0] IMPLICIT OCTET STRING (SIZE(6))
-- Constructed as follows: A single DES block
-- of eight octets is constructed from the two
-- integers in the timestamp. First four bytes
-- are the high order integer encoded MSB
-- first; Last four bytes are the low order
-- integer encoded MSB first. The block is
-- encrypted using the shared DES key, and
-- the first six bytes are the OCTET STRING.
-- With the [0] type and 6-byte length, the
-- MutualAuthenticationToken has a fixed
-- length of eight bytes.
}
END
4.2 Encoding Rules
Whenever a structure is to be signed it must always be constructed
the same way. This is particularly important where a signed structure
has to be reconstructed by the recipient before the signature is
verified. The rules listed below are taken from X.509.
- the definite form of length encoding shall be used, encoded in
the minimum number of octets;
- for string types, the constructed form of encoding shall not
be used;
- if the value of a type is its default value, it shall be
absent;
- the components of a Set type shall be encoded in ascending
order of their tag value;
- the components of a Set-of type shall be encoded in ascending
order of their octet value;
- if the value of a Boolean type is true, the encoding shall
have its contents octet set to `FF'16;
- each unused bits in the final octet of the encoding of a
BitString value, if there are any, shall be set to zero;
- the encoding of a Real type shall be such that bases 8, 10 and
16 shall not be used, and the binary scaling factor shall be
zero.
4.3 Version numbers and forward compatibility
The LoginTicket and AuthenticationToken structures contain a
three octet version identifier which is intended to ease
transition to future revisions of this architecture. The default
value, and the value which should always be supplied by
implementations of this version of the architecture is 0.0.0
(three zero octets). The first octet is the major version. An
implementation of this version of the architecture should refuse
to process data structures where it is other than zero, because
changing it indicates that the interpretation of some subsidiary
data structure has changed. The second octet is the minor
version. An implementation of this version of the architecture
should ignore the value of this octet. Some future version of
the architecture may set a value other than zero and may specify
some different processing of the remainder of the structure based
on that different value. Such a change would be backward compatible
and interoperable. The third octet is the ECO revision. No
implementation should make any processing decisions based on the
value of that octet. It may be logged, however, to help in
debugging interoperability problems.
In the CDC protocol, there is also a three octet version
numbering scheme, where versions 1.0.0 and 2.0.0 have been
defined. Implementations should follow the same rules above and
reject major version numbers greater than 2.
ASN.1 is inherently extensible because it allows new fields to be
added "onto the end" of existing data structures in an
unambiguous way. Implementations of DASS are encouraged to
ignore any such additional fields in order to enhance backwards
compatibility with future versions of the architecture.
Unfortunately, commonly available ASN.1 compilers lack this
capability, so this behavior cannot reasonably be required and
may limit options for future extensions.
4.4 Cryptographic Encoding
Some of the substructures listed in the previous sections are
specified as ENCRYPTED OCTET STRINGs containing encrypted
information. DASS uses the DES, RSA, and MD2 cryptosystems Each
of those cryptosystems specifies a function from octet string
into another in the presence of a key (except MD2, which is
keyless). This section describes how to form the octet strings
on which the DES and RSA operations are performed.
4.4.1 Algorithm Independence vs. Key Parity
All of the defined encodings for DASS for secret key encryption
are based on DES. It is intended, however, that other
cryptosystems could be substituted without any other changes for
formats or algorithms. The required "form factor" for such a
cryptosystem is that it have a 64 bit key and operate on 64 bit
blocks (this appears to be a common form factor for a
cryptosystem). For this reason, DES keys are in all places
treated as though they were 64 bits long rather than 56. Only in
the operation of the algorithm itself are eight bits of the key
dropped and key parity bits substituted. Choosing a key always
involves picking a 64 bit random number.
4.4.2 Password Hashing
Encrypted credentials are encrypted using DES as described in the
next section. The key for that encryption is derived from the
user's password and name by the following algorithm:
a) Put the rightmost RDN of the user's name in canonical form
according to BER and the X.509 encoding rules. For any string
types that are case insensitive, map to upper case, and where
matching is independent of number of spaces collapse all
multiple spaces to a single space and delete leading and
trailing spaces.
Note: the RDN is used to add "salt" to the hash calculation
so that someone can't precompute the hash of all the words in
a dictionary and then apply them against all names. Deriving
the salt from the last RDN of the name is a compromise. If it
were derived from the whole name, all encrypted keys would be
obsoleted when a branch of the namespace was renamed. If it
were independent of name, interaction with a login agent would
take two extra messages to retrieve the salt. With this
scheme, encrypted keys are obsoleted by a change in the last
RDN and if a final RDN is common to a large number of users,
dictionary attacks against them are easier; but the common
case works as desired.
b) Compute TEMP as the MD2 message digest of the concatenation of
the password and the RDN computed above.
c) Repeat the following 40 times: Use the first 64 bits of TEMP
as a DES key to encrypt the second 64 bits; XOR the result
with the first 64 bits of TEMP; and compute a new TEMP as MD2
of the 128 bit result.
d) Use the final 64 bits of the result (called hash1) as the key
to decrypt the encrypted credentials. Use the first 64 bits
(called hash2) as the proof of knowledge of the password for
presentation to a login agent (if any).
4.4.3 Digital DEA encryption
DES encryption is used in the following places:
- In the encryption of the encrypted credentials structure
- To encrypt the delegator in authentication tokens
- To encrypt the time in the mutual authenticator
In the first two cases, a varying length block of information
coded in ASN.1 is encrypted. This is done by dividing the block
of information into 8 octet blocks, padding the last block with
zero bytes if necessary, and encrypting the result using the CBC
mode of DES. A zero IV is used.
In the third case, a fixed length (8 byte) quantity (a timestamp)
is encrypted. The timestamp is mapped to a byte string using
"big endian" order and the block is encrypted using the ECB mode
of DES.
4.4.4 Digital MAC Signing
DES signing is used in the Authenticator. Here, the signature is
computed over an ASN.1 structure. The signature is the CBC residue
of the structure padded to a multiple of eight bytes with zeros. The
CBC is computed with an IV of zero.
4.4.5 RSA Encryption
RSA encryption is used in the Encrypted Shared Key. RSA encryption
is best thought of as operating on blocks which are integers rather
than octet strings and the results are also integers. Because an RSA
encryption permutes the integers between zero and (modulus-1), it is
generally thought of as acting on a block of size (keysizeinbits-1)
and producing a block of size (keysizeinbits) where keysizeinbits is
the smallest number of bits in which the modulus can be represented.
DASS only supports key sizes which are a multiple of eight bits (This
restriction is only required to support interoperation with certain
existing implementations. If the key size is not a multiple of eight
bits, the high order byte may not be able to hold values as large as
the mandated '64'. This is not a problem so long as the two high
order bytes together are non-zero, but certain early implementations
check for the value '64' and will not interoperate with
implementations that use some other value.).
The encrypted shared key structure is laid out as follows:
- The DES key to be shared is placed in the last eight bytes
- The POSIX format creation time encoded in four bytes using big
endian byte order is placed in the next four (from the end)
bytes
- The POSIX format expiration time encoded in four bytes using
big endian byte order is placed in the next four (from the
end) bytes
- Four zero bytes are placed in the next four (from the end)
bytes
- The first byte contains the constant '64' (decimal)
- All remaining bytes are filled with random bytes (the security
of the system does not depend on the cryptographic randomness
of these bytes, but they should not be a frequently repeating
or predictable value. Repeating the DES key from the last
bytes would be good).
The RSA algorithm is applied to the integer formed by treating the
bytes above as an integer in big endian order and the resulting
integer is converted to a BIT STRING by laying out the integer in
'big endian' order.
On decryption, the process is reversed; the decryptor should verify
the four explicitly zero bytes but should not verify the contents of
the high order byte or the random bytes.
4.4.6 oiwMD2withRSA Signatures
RSA-MD2 signatures are used on certificates, login tickets, shared
key tickets, and node tickets. In all cases, a signature is computed
on an ASN.1 encoded string using an RSA private key. This is done as
follows:
- The MD2 algorithm is applied to the ASN.1 encoded string to
produce a 128 bit message digest
- The message digest is placed in the low order bytes of the RSA
block (big endian)
- The next two lowest order bytes are the ASN.1 'T' and 'L' for
an OCTET STRING.
- The remainder of the RSA block is filled with zeros
- The RSA operation is performed, and the resulting integer is
converted to an octet string by laying out the bytes in big
endian order.
On verification, a value like the above or one where the message
digest is present but the 'T' and 'L' are missing (zero) should be
accepted for backwards compatibility with an earlier definition of
this crypto algorithm.
4.4.7 decMD2withRSA Signatures
This algorithm is the same as the oiwMD2withRSA algorithm as defined
above. We allocated an algorithm object identifier from the Digital
space in case the definition of that OID should change. It will not
be used unless the meaning of oiwMD2withRSA becomes unstable.
Annex A
Typical Usage
This annex describes one way a system could use DASS services (as
described in section 3) to provide security services. While this
example provided motivation for some of the properties of DASS, it is
not intended to represent the only way that DASS may be used. This
goes through the steps that would be needed to install DASS "from
scratch".
A.1 Creating a CA
A CA is created by initializing its state. Each CA can sign
certificates that will be placed in some directory in the name
service. Before these certificates will be believed in a wider
context than the sub-tree of the name space which is headed by that
directory, the CA must be certified by a CA for the parent directory.
The procedure below accomplishes this. For most secure operation, the
CA should run on an off-line system and communicate with the rest of
the network by interchanging files using a simple specialized
mechanism such as an RS232 line or a floppy disk. It is assumed that
access to the CA is controlled and that the CA will accept
instructions from an operator.
- Call Install_CA to create the CA State.
This state is saved within the CA system and is never
disclosed.
- If this is the first CA in the namespace and the CA is
intended to certify only members of a single directory, we are
done. Otherwise, the new CA must be linked into the CA
hierarchy by cross-certifying the parent and children of this
CA. There is no requirement that CA hierarchies be created
from the root down, but to simplify exposition, only this case
will be described. The newly created CA must learn its name,
its UID, the UID of its parent directory, and the public key
of the parent directory CA by some out of band reliable means.
Most likely, this would be done by looking up the information
in the naming service and asking the CA operator to verify it.
The CA then forms this information into a parent certificate
and signs it using the Create_certificate function. It
communicates the certificate to the network and posts it in
the naming service.
- This name, UID, and public key of the new CA are taken to the
CA of the parent directory, which verifies it (again by some
unspecified out-of-band mechanism) and calls
Create_Certificate to create a child certificate using its own
Name and UID in the issuer fields. This certificate is also
placed in the naming service.
A CA can sign certificates for more than one directory. In this case
it is possible that a single CA will take the role of both CAs in the
example above. The above procedure can be simplified in this case, as
no interchange of information is required.
A.2 Creating a User Principal
A system manager may create a new user principal by invoking the
Create_principal function supplying the principal's name, UID, and
the public key/UID of the parent CA. The public key and UID must be
obtained in a reliable out of band manner. This is probably by
having knowledge of that information "wired into" the utility which
creates new principals. At account creation time, the system manager
must supply what will become the user's password. This might be done
by having the user present and directly enter a password or by having
the password selected by some random generator.
The trusted authority certificate and corresponding user public key
generated by the Create_principal function are sent to the CA which
verifies its contents (again by an out-of-band mechanism) and signs a
corresponding certificate. The encrypted credentials, CA signed
certificate, and trusted authority certificates are all placed in the
naming service. The process by which the password is made known to
the user must be protected by some out-of-band mechanism.
In some cases the principal may wish to generate its own key, and not
use the Encrypted_Credentials. (e.g., if the Principal is represented
by a Smart Card). This may be done using a procedure similar to the
one for creating a new CA.
A.3 Creating a Server Principal
A server also has a public/private key pair. Conceptually, the same
procedure used to create a user principal can be used to create a
server. In practice, the most important difference is likely to be
how the password is protected when installing it on a server compared
to giving it to a user.
A server may wish to retrieve (and store) its Encrypted Credentials
directly and never have them placed in the naming service. In this
case some other mechanism can be used (e.g., passing the floppy disk
containing the encrypted credentials to the server). This would
require a variant of the Initialize_Server routine which does not
fetch the Encrypted Credentials from the naming service.
A.4 Booting a Server Principal
When the server first boots it needs its name (unreliably) and
password (reliably). It then calls Initialize_Server to obtain its
credentials and trusted authority certificates (which it will later
need in order to authenticate users). These credentials never time
out, and are expected to be saved for a long time. In particular the
associated Incoming Timestamp List must be preserved while there are
any timestamps on it. It is desirable to preserve the Cached Incoming
Contexts as long as there are any contexts likely to be reused.
If a server wants to initiate associations on its own behalf then it
must call Generate_Server_Ticket. It must repeat this at intervals
if the expiration period expires.
A node that wishes to do node authentication (or which acts as a
server under its own name) must be created as a server.
A.5 A user logs on to the network
The system that the user logs onto finds the user's name and
password. It then calls Network_Login to obtain credentials for the
user. These credentials are saved until the user wants to make a
network connection. The credentials have a time limit, so the user
will have to obtain new credentials in order to make connections
after the time limit. The credentials are then checked by calling
Verify_Principal_Name, in order to check that the key specified in
the encrypted credentials has been certified by the CA.
If the system does source node authentication it will call
Combine_credentials, once the local username has been found. (This
can either be found by looking the principal's global name up in a
file, or the user can be asked to give the local name directly.
Alternatively the user can be asked to give his local username, which
the system looks up to find the global name).
A.6 An Rlogin (TCP/IP) connection is made
When the user calls a modified version of the rlogin utility, it
calls Create_token in order to create the Initial Authentication
Token, which is passed to the other system as part of the rlogin
protocol. The rlogind utility at the destination node calls
Accept_token to verify it. It then looks up in a local rhosts-like
database to determine whether this global user is allowed access to
the requested destination account. It calls Verify_principal_name
and/or Verify_node_name to confirm the identity of the requester. If
access is allowed, the connection is accepted and the Mutual
Authentication Token is returned in the response message.
The source receives the returned Mutual Authentication Token and uses
it to confirm it communicating with the correct destination node.
Rlogind then calls Combine_credentials to combine its node/account
information with the global user identification in the received
credentials in case the user accesses any network resources from the
destination system.
A.7 A Transport-Independent Connection
As an alternative to the description in A.6, an application wishing
to be portable between different underlying transports may call
create_token to create an authentication token which it then sends to
its peer. The peer can then call accept_token and
verify_principal_name and learn the identity of the requester.
Annex B
Support of the GSSAPI
In order to support applications which need to be portable across a
variety of underlying security mechanisms, a "Generic Security
Service API" (or GSSAPI) was designed which gives access to a common
core of security services expected to be provided by several
mechanisms. The GSSAPI was designed with DASS, Kerberos V4, and
Kerberos V5 in mind, and could be written as a front end to any or
all of those systems. It is hoped that it could serve as an
interface to other security systems as well.
Application portability requires that the security services supported
be comparable. Applications using the GSSAPI will not be able to
access all of the features of the underlying security mechanisms.
For example, the GSSAPI does not allow access to the "node
authentication" features of DASS. To the extent the underlying
security mechanisms do not support all the features of GSSAPI,
applications using those features will not be portable to those
security mechanisms. For example, Kerberos V4 does not support
delegation, so applications using that feature of the GSSAPI will not
be portable to Kerberos V4.
This annex explains how the GSSAPI can be implemented using the
primitive services provided by DASS.
B.1 Summary of GSSAPI
The latest draft of the GSSAPI specification is available as an
internet draft. The following is a brief summary of that evolving
document and should not be taken as definitive. Included here are
only those aspects of GSSAPI whose implementation would be DASS
specific.
The GSSAPI provides four classes of functions: Credential Management,
Context-Level Calls, Per-message calls, and Support Calls; two types
of objects: Credentials and Contexts; and two kinds of data
structures to be transmitted as opaque byte strings: Tokens and
Messages. Credentials hold keys and support information used in
creating tokens. Contexts hold keys and support information used in
signing and encrypting messages.
The Credential Management functions of GSSAPI are "incomplete" in the
sense that one could not build a useful security implementation using
only GSSAPI. Functions which create credentials based on passwords
or smart cards are needed but not provided by GSSAPI. It is
envisioned that such functions would be invoked by security mechanism
specific functions at user login or via some separate utility rather
than from within applications intended to be portable. The
Credential Management functions available to portable applications
are:
- GSS_Acquire_cred: get a handle to an existing credential
structure based on a name or process default.
- GSS_Release_cred: release credentials after use.
The Context-Level Calls use credentials to establish contexts.
Contexts are like connections: they are created in pairs and are
generally used at the two ends of a connection to process messages
associated with that connection. The Context-Level Calls of interest
are:
- GSS_Init_sec_context: given credentials and the name of a
destination, create a new context and a token which will
permit the destination to create a corresponding context.
- GSS_Accept_sec_context: given credentials and an incoming
token, create a context corresponding to the one at the
initiating end and provide information identifying the
initiator.
- GSS_Delete_sec_context: delete a context after use.
The Per-Message Calls use contexts to sign, verify, encrypt, and
decrypt messages between the holders of matching contexts. The Per-
Message Calls are:
- GSS_Sign: Given a context and a message, produces a string of
bytes which constitute a signature on a provided message.
- GSS_Verify: Given a context, a message, and the bytes
returned by GSS_Sign, verifies the message to be authentic
(unaltered since it was signed by the corresponding context).
- GSS_Seal: Given a context and a message, produces a string of
bytes which include the message and a signature; the message
may optionally be encrypted.
- GSS_Unseal: Given a context and the string of bytes from
GSS_Seal, returns the original message and a status indicating
its authenticity.
The Support Calls provide utilities like translating names and status
codes into printable strings.
B.2 Implementation of GSSAPI over DASS
B.2.1 Data Structures
The objects and data structures of the GSSAPI do not map neatly into
the objects and data structures of the DASS architecture.
This section describes how those data structures can be implemented
using the DASS data structures and primitives
Credential handles correspond to the credentials structures in DASS,
where the portable API assumes that the credential structures
themselves are kept from applications and handles are passed to and
from the various subroutines.
Context initialization tokens correspond to the tokens of DASS. The
GSSAPI prescribes a particular ASN.1 encoded form for tokens which
includes a mechanism specific bit string within it. An
implementation of GSSAPI should enclose the DASS token within the
GSSAPI "wrapper".
Context handles have no corresponding structure in DASS. The
Create_token and Accept_token calls of DASS return a shared key and
instance identifier. An implementation of the GSSAPI must take those
values along with some other status information and package it as a
"context" opaque structure. These data structures must be allocated
and freed with the appropriate calls.
Per-message tokens and sealed messages have no corresponding data
structure within DASS. To fully support the GSSAPI functionality,
DASS must be extended to include this functionality. These data
structures are created by cryptographic routines given the keys and
status information in context structures and the messages passed to
them. While not properly part of the DASS architecture, the formats
of these data structures are included in section C.3.
B.2.2 Procedures
This section explains how the functions of the GSSAPI can be provided
in terms of the Services Provided by DASS. Not all of the DASS
features are accessible through the GSSAPI.
B.2.2.1 GSS_Acquire_cred
The GSSAPI does not provide a mechanism for logging in users or
establishing server credentials. It assumes that some system specific
mechanism created those credentials and that applications need some
mechanism for getting at them. A model implementation might save all
credentials in a node-global pool indexed by some sort of credential
name. The credentials in the pool would be access controlled by some
local policy which is not concern of portable applications. Those
applications would simply call GSS_Acquire_cred and if they passed
the access control check, they would get a handle to the credentials
which could be used in subsequent calls.
B.2.2.2 GSS_Release_cred
This call corresponds to the "delete_credentials" call of DASS.
B.2.2.3 GSS_Init_sec_context
In the course of a normal mutual authentication, this routine will be
called twice. The procedure can determine whether this is the first
or second call by seeing whether the "input_context_handle" is zero
(it will be on the first call). On the first call, it will use the
DASS Create_token service to create a token and it will also allocate
and populate a "context" structure. That structure will hold the key,
instance identifier, and mutual authentication token returned by
Create_token and will in addition hold the flags which were passed
into the Init_sec_context call. The token returned by
Init_sec_context will be the DASS token included in the GSSAPI token
"wrapper". The DASS token will include the optional principal name.
If mutual authentication is not requested in the GSSAPI call, the
mutual authentication token returned by DASS will be ignored and the
initial call will return a COMPLETE status. If mutual authentication
is requested, the mutual authentication token will be stored in the
context information and a CONTINUE_NEEDED status returned.
On the second call to GSS_Init_sec_context (with input_context_handle
non-zero), the returned token will be compared to the one in the
context information using the Compare_mutual_token procedure and a
COMPLETE status will be returned if they match.
B.2.2.4 GSS_Accept_sec_context
This routine in GSSAPI accepts an incoming token and creates a
context. It combines the effects of a series of DASS functions. It
could be implemented as follows:
- Remove the GSSAPI "wrapper" from the incoming token and pass
the rest and the credentials to "Accept_token". Accept_token
produces a mutual authentication token and a new credentials
structure. If delegation was requested, the new credentials
structure will be an output of GSS_Accept_sec_context. In any
case, it will be used in the subsequent steps of this
procedure.
- Use the DASS Get_principal_name function to extract the
principal name from the credentials produced by Accept_token.
This name is one of the outputs of "GSS_Accept_sec_context.
- Apply the DASS Verify_principal_name to the new credentials
and the retrieved name to authenticate the token as having
come from the named principal.
- Create and populate a context structure with the key and
timestamp returned by Accept_token and a status of COMPLETE.
Return a handle to that context.
- If delegation was requested, return the new credentials from
GSS_Accept_sec_context. Otherwise, call Delete_credentials.
- If mutual authentication was requested, wrap the mutual
authentication token from Accept_token in a GSSAPI "wrapper"
and return it. Otherwise return a null string.
B.2.2.5 GSS_Delete_sec_context
This routine simply deletes the context state. No calls to DASS are
required.
B.2.2.6 GSS_Sign
This routine takes as input a context handle and a message. It
creates a per_msg_token by computing a digital signature on the
message using the key and timestamp in the context block. No DASS
services are required. If additional cryptographic services were
requested (replay detection or sequencing), a timestamp or sequence
number must be prepended to the message and sent with the signature.
The syntax for this message is listed in section C.3.
B.2.2.7 GSS_Verify
This routine repeats the calculation of the sign routine and verifies
the signature provided. If replay detection or sequencing services
are provided, the context must maintain as part of its state
information containing the sequence numbers or timestamps of messages
already received and this one must be checked for acceptability.
B.2.2.8 GSS_Seal
This routine performs the same functions as Sign but also optionally
encrypts the message for privacy using the shared key and
encapsulates the whole thing in a GSSAPI specified ASN.1 wrapper.
B.2.2.9 GSS_Unseal
This routine performs the same functions as GSS_Verify but also
parses the data structure including the signature and message and
decrypts the message if necessary.
B.3 Syntax
The GSSAPI specification recommends the following ASN.1 encoding for
the tokens and messages generated through the GSSAPI:
--optional top-level token definitions to frame
-- different mechanisms
GSSAPI DEFINITIONS ::=
BEGIN
MechType ::= OBJECT IDENTIFIER
-- data structure definitions
ContextToken ::=
-- option indication (delegation, etc.) indicated
-- within mechanism-specific token
[APPLICATION 0] IMPLICIT SEQUENCE {
thisMech MechType,
responseExpected BOOLEAN,
innerContextToken ANY DEFINED BY MechType
-- contents mechanism-specific
}
PerMsgToken ::=
-- as emitted by GSS_Sign and processed by
-- GSS_Verify
[APPLICATION 1] IMPLICIT SEQUENCE {
thisMech MechType,
innerMsgToken ANY DEFINED BY MechType
-- contents mechanism-specific
}
SealedMessage ::=
-- as emitted by GSS_Seal and processed by
-- GSS_Unseal
[APPLICATION 2] IMPLICIT SEQUENCE {
sealingToken PERMSGTOKEN,
confFlag BOOLEAN,
userData OCTET STRING
-- encrypted if confFlag TRUE
}
The object identifier for the DASS MechType is 1.3.12.2.1011.7.5.
The innerContextToken of a token is a DASS token or mutual
authentication token.
The innerMsgToken is a null string in the case where the message is
encrypted and the token is included as part of a SealedMessage.
Otherwise, it is an eight octet sequence computed as the CBC residue
computed using a key and string of bytes defined as follows:
- Pad the message provided by the application with 1-8 bytes of
pad to produce a string whose length is a multiple of 8
octets. Each pad byte has a value equal to the number of pad
bytes.
- Compute the key by taking the timestamp of the association
(two four byte integers laid out in big endian order with the
most significant integer first), complementing the high order
bit (to avoid aliasing with mutual authenticators), and
encrypting the block in ECB mode with the shared key of the
association.
The userData field of a SealedMessage is exactly the application
provided byte string if confFlag=FALSE. Otherwise, it is the
application supplied message encrypted as follows:
- Pad the message provided by the application with 1-8 bytes of
pad to produce a string whose length = 4 (mod 8). Each pad
byte has a value equal to the number of pad bytes.
- Append a four byte CRC32 computed over the message + pad.
- Compute a key by taking the timestamp of the association (two
four byte integers laid out in big endian order with the most
significant integer first), complementing the high order bit
(to avoid aliasing with mutual authenticators), and encrypting
the block in ECB mode with the shared key of the association.
- Encrypt the message + pad + CRC32 using CBC and the key
computed in the previous step.
A note of the logic behind the above:
- Because the shared key of an association may be reused by many
associations between the same pair of principals, it is
necessary to bind the association timestamp into the messages
somehow to prevent messages from a previous association being
replayed into a new sequence. The technique above of
generating an association key accomplishes this and has a side
benefit. An implementation may with to keep the long term
keys out of the hands of applications for purposes of
confinement but may wish to put the encryption associated with
an association in process context for reasons of performance.
Defining an association key makes that possible.
- The reason that the association specific key is not specified
as the output of Create_token and Accept_token is that the DCE
RPC security implementation requires that a series of
associations between two principals always have the same key
and we did not want to have to support a different interface
in that application.
- The CRC32 after pad constitutes a cheap integrity check when
data is encrypted.
- The fact that padding is done differently for encrypted and
signed messages means that there are no threats related to
sending the same message encrypted and unencrypted and using
the last block of the encrypted message as a signature on the
unencrypted one.
Annex C
Imported ASN.1 definitions
This annex contains extracts from the ASN.1 description of X.509 and
X.500 definitions referenced by the DASS ASN.1 definitions.
CCITT DEFINITIONS ::=
BEGIN joint-iso-ccitt OBJECT IDENTIFIER ::= {2} ds
OBJECT IDENTIFIER ::= {joint-iso-ccitt 5} algorithm
OBJECT IDENTIFIER ::= {ds 8}
iso OBJECT IDENTIFIER ::= {1} identified-
organization OBJECT IDENTIFIER ::= {iso 3} ecma OBJECT
IDENTIFIER ::= {identified-organization 12} digital
OBJECT IDENTIFIER ::= { ecma 1011 }
-- X.501 definitions
AttributeType ::= OBJECT IDENTIFIER AttributeValue ::= ANY
-- useful ones are
-- OCTET STRING ,
-- PrintableString ,
-- NumericString ,
-- T61String ,
-- VisibleString
AttributeValueAssertion ::= SEQUENCE {AttributeType,
AttributeValue}
Name ::= CHOICE {-- only one possibility for now --
RDNSequence}
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
DistinguishedName ::= RDNSequence
RelativeDistinguishedName ::= SET OF AttributeValueAssertion
-- X.509 definitions
Certificate ::= SIGNED SEQUENCE {
version [0] Version DEFAULT 1988 ,
serialNumber SerialNumber ,
signature AlgorithmIdentifier ,
issuer Name,
valid Validity,
subject Name,
subjectPublicKey SubjectPublicKeyInfo }
Version ::= INTEGER { 1988(0)} SerialNumber ::= INTEGER Validity
::= SEQUENCE{
notBefore UTCTime,
notAfter UTCTime}
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier ,
subjectPublicKey BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ,
parameters ANY DEFINED BY algorithm OPTIONAL}
ALGORITHM MACRO BEGIN TYPE NOTATION ::= "PARAMETER" type VALUE
NOTATION ::= value (VALUE OBJECT IDENTIFIER) END -- of ALGORITHM
ENCRYPTED MACRO BEGIN TYPE NOTATION ::=type(ToBeEnciphered) VALUE
NOTATION ::= value(VALUE BIT STRING)
-- the value of the bit string is generated by
-- taking the octets which form the complete
-- encoding (using the ASN.1 Basic Encoding Rules)
-- of the value of the ToBeEnciphered type and
-- applying an encipherment procedure to those octets-- END
SIGNED MACRO ::= BEGIN TYPE NOTATION ::= type (ToBeSigned) VALUE
NOTATION ::= value(VALUE SEQUENCE{
ToBeSigned,
AlgorithIdentifier, -- of the algorithm used to generate
-- the signature
ENCRYPTED OCTET STRING
-- where the octet string is the result
-- of the hashing of the value of "ToBeSigned" END -- of
SIGNED
SIGNATURE MACRO ::= BEGIN TYPE NOTATION ::= type(OfSignature) VALUE
NOTATION ::= value(VALUE
SEQUENCE{
AlgorithmIdentifier,
-- of the algorithm used to compute the signature
ENCRYPTED OCTET STRING
-- where the octet string is a function (e.g., a
-- compressed or hashed version) of the value
-- "OfSignature", which may include the identifier
-- of the algorithm used to compute
-- the signature--}
) END -- of SIGNATURE
-- X.509 Annex H (not part of the standard)
encryptionAlgorithm OBJECT IDENTIFIER ::= {algorithm 1} rsa ALGORITHM
PARAMETER KeySize
::= {encryptionAlgorithm 1}
KeySize ::= INTEGER
END
Glossary
authentication
The process of determining the identity
(usually the name) of the other party in some communication
exchange.
authentication context
Cached information used during a particular instance of
authentication and including a shared symmetric (DES) key as
well as components of the authentication token conveyed
during establishment of this context.
authentication token
Information conveyed during a strong authentication exchange
that can be used to authenticate its sender. An
authentication token can, but is not necessarily limited to,
include the claimant identity and ticket, as well as signed
and encrypted secret key exchange messages conveying a
secret key to be used in future cryptographic operations. An
authentication token names a particular protocol data
structure component.
authorization
The process of determining the rights
associated with a particular principal.
certificate
The public key of a particular principal, together
with some other information relating to the names of the
principal and the certifying authority, rendered unforgeable
by encipherment with the private key of the certification
authority that issued it.
certification authority
An authority trusted by one or more principals to create and
assign certificates.
claimant
The party that initiates the authentication process.
In the DASS architecture, claimants possess credentials
which include their identity, authenticating private key and
a ticket certifying their authenticating public key.
credentials
Information "state" required by principals in order
to for them to authenticate. Credentials may contain
information used to initiate the authentication process
(claimant information), information used to respond to an
authentication request (verifier information), and cached
information useful in improving performance.
cryptographic checksum
Information which is derived by performing a cryptographic
transformation on the data unit. This information can be
used by the receiver to verify the authenticity of data
passed in cleartext
decipher
To reverse the effects of encipherment and render a
message comprehensible by use of a cryptographic key.
delegation
The granting of temporary credentials that allow a
process to act on behalf of a principal.
delegation key
A short term public/private key pair used by a claimant
to act on behalf of a principal for a bounded period. The
delegation public key appears in the ticket, whereas the
delegation private key is used to sign secret key exchange
messages.
DES
Data Encryption Standard: a symmetric (secret key)
encryption algorithm used by DASS. An alternate encryption
algorithm could be substituted with little or no disruption
to the architecture.
DES key
A 56-bit secret quantity used as a parameter to the
DES encryption algorithm.