5.2. Basic Kerberos Types
本节定义了在整个 Kerberos 协议中可能使用的多个基本类型。
5.2.1. KerberosString
RFC 1510 中 Kerberos 协议的原始规范在多个地方使用 GeneralString 来表示人类可读的字符串数据。Kerberos 的历史实现无法利用 GeneralString 的全部功能。此 ASN.1 类型需要使用 ISO-2022/ECMA-35 中指定的指定和调用转义序列来切换字符集,指定为 G0 的默认字符集是 ISO-646/ECMA-6 国际参考版本 (IRV)(也称为美国 ASCII),这在大多数情况下都有效。
ISO-2022/ECMA-35 定义了四个字符集代码元素 (G0..G3) 和两个控制功能代码元素 (C0..C1)。DER 禁止将字符集指定为除 G0 和 C0 集之外的任何字符集。不幸的是,这似乎会产生禁止使用 ISO-8859 (ISO Latin) 字符集或任何其他使用 96 字符集的字符集的副作用,因为 ISO-2022/ECMA-35 禁止将它们指定为 G0 代码元素。ASN.1 标准社区正在调查这种副作用。
实际上,许多实现将 GeneralString 视为实现默认的任何字符集的 8 位字符串,而不考虑正确使用字符集指定转义序列。默认字符集通常由当前用户依赖于操作系统的区域设置确定。至少有一个主要实现在 GeneralString 中放置了未转义的 UTF-8 编码的 Unicode 字符。这种不遵守 GeneralString 规范的做法会导致当 Kerberos 客户端、服务和 KDC 使用冲突的字符编码时出现互操作性问题。
这种不幸的情况是由于在先前的 Kerberos 规范中对 ASN.1 GeneralString 类型的限制文档不当造成的。
新的 (RFC 1510 之后的) 类型 KerberosString 定义如下,它是一个被约束为仅包含 IA5String 中的字符的 GeneralString。
KerberosString ::= GeneralString (IA5String)
通常,不应在 KerberosString 中使用 US-ASCII 控制字符。不应在主体名称或领域名称中使用控制字符。
为了兼容性,实现可以选择接受包含 IA5String 允许的字符以外的字符的 GeneralString 值,但它们应该意识到字符集指定代码可能不存在,并且编码几乎在所有方面都应该被视为特定于区域设置的。实现也可以选择发出超出 IA5String 允许的 GeneralString 值,但它们应该意识到这样做从互操作性的角度来看风险极大。
一些现有实现使用 GeneralString 来编码未转义的特定于区域设置的字符。这违反了 ASN.1 标准。这些实现中的大多数在左半部分编码 US-ASCII,因此只要实现仅传输 US-ASCII,就不会在这方面违反 ASN.1 标准。一旦这样的实现编码具有高位设置的未转义的特定于区域设置的字符,它就违反了 ASN.1 标准。
已知其他实现使用 GeneralString 来包含 UTF-8 编码。这也违反了 ASN.1 标准,因为 UTF-8 是不同的编码,而不是 ISO 2022 定义的 94 或 96 字符的 "G" 集。据信这些实现甚至不使用 ISO 2022 转义序列来改变字符编码。即使实现通过使用该转义序列来宣布编码更改,ASN.1 标准也禁止使用除用于指定/调用 GeneralString 允许的 "G" 或 "C" 集的转义序列之外的任何转义序列。
该协议的未来修订版几乎肯定会允许更具互操作性的主体名称表示,可能包括 UTF8String。
请注意,将新约束应用于先前未约束的类型构成创建新的 ASN.1 类型。在这种特殊情况下,更改不会导致 DER 下的编码发生变化。
5.2.2. Realm 和 PrincipalName
Realm ::= KerberosString
PrincipalName ::= SEQUENCE {
name-type [0] Int32,
name-string [1] SEQUENCE OF KerberosString
}
Kerberos 领域名称编码为 KerberosString。领域不得包含代码为 0 的字符 (US-ASCII NUL)。大多数领域通常由几个以句点 (.) 分隔的组件组成,采用 Internet 域名样式,或由斜杠 (/) 分隔,采用 X.500 名称样式。第 6.1 节规定了领域名称的可接受形式。PrincipalName 是由以下子字段组成的组件的类型化序列:
name-type
此字段指定后面的名称类型。此字段的预定义值在第 6.2 节中指定。name-type 应被视为提示。忽略名称类型,没有两个名称可以相同 (即,至少一个组件或领域必须不同)。
name-string
此字段编码形成名称的组件序列,每个组件编码为 KerberosString。PrincipalName 和 Realm 一起形成主体标识符。大多数 PrincipalName 只有几个组件 (通常是一个或两个)。
5.2.3. KerberosTime
KerberosTime ::= GeneralizedTime -- with no fractional seconds
Kerberos 中使用的时间戳编码为 GeneralizedTime。KerberosTime 值不得包含秒的任何小数部分。根据 DER 的要求,它还不得包含任何分隔符,并且它必须指定 UTC 时区 (Z)。示例: 1985 年 11 月 6 日晚上 9 点后 6 分钟 27 秒的 UTC 时间的唯一有效格式是 19851106210627Z。
5.2.4. 受约束的整数类型
类型的某些整数成员应该被约束为可在 32 位中表示的值,以便与合理的实现限制兼容。
Int32 ::= INTEGER (-2147483648..2147483647)
-- signed values representable in 32 bits
UInt32 ::= INTEGER (0..4294967295)
-- unsigned 32 bit values
Microseconds ::= INTEGER (0..999999)
-- microseconds
尽管这导致抽象类型与 RFC 1510 版本相比发生了变化,但 DER 中的编码应该保持不变。历史实现通常仅限于 32 位整数值,并且分配的数字应该落在 32 位可表示的整数值空间中,以促进互操作性。
消息中的几个整数字段被约束为固定值。
pvno
也称为 TKT-VNO 或 AUTHENTICATOR-VNO,此重复出现的字段始终是常量整数 5。没有简单的方法将此字段变成有用的协议版本号,因此其值是固定的。
msg-type
此整数字段通常与包含消息类型的应用程序标记号相同。
5.2.5. HostAddress 和 HostAddresses
HostAddress ::= SEQUENCE {
addr-type [0] Int32,
address [1] OCTET STRING
}
-- NOTE: HostAddresses is always used as an OPTIONAL field and
-- should not be empty.
HostAddresses -- NOTE: subtly different from rfc1510,
-- but has a value mapping and encodes the same
::= SEQUENCE OF HostAddress
主机地址编码由两个字段组成:
addr-type
此字段指定后面的地址类型。此字段的预定义值在第 7.5.3 节中指定。
address
此字段编码 addr-type 类型的单个地址。
5.2.6. AuthorizationData
-- NOTE: AuthorizationData is always used as an OPTIONAL field and
-- should not be empty.
AuthorizationData ::= SEQUENCE OF SEQUENCE {
ad-type [0] Int32,
ad-data [1] OCTET STRING
}
ad-data
此字段包含要根据相应 ad-type 字段的值解释的授权数据。
ad-type
此字段指定 ad-data 子字段的格式。所有负值都保留供本地使用。非负值保留供注册使用。
每个类型和数据序列称为授权元素。元素可能是特定于应用程序的; 但是,有一组通用的递归元素,所有实现都应该理解。这些元素包含嵌入在其中的其他元素,封装元素的解释决定了必须解释哪些嵌入元素,哪些可以忽略。
这些通用授权数据元素是递归定义的,这意味着这些类型的 ad-data 本身将包含一系列授权数据,其解释受封装元素的影响。根据封装元素的含义,封装的元素可能会被忽略,可能会被解释为由 KDC 直接发出,或者可能会存储在票证的单独明文部分中。封装元素的类型被指定为 Kerberos 规范的一部分,因为基于这些值的行为应该在实现之间被理解,而其他元素只需要被它们影响的应用程序理解。
如果授权数据元素存在于票证或认证器中,则认为它们是关键的。如果服务器在 AP-REQ 中或 AP-REQ 中包含的票证中接收到未知的授权数据元素类型,那么,除非它被封装在已知的授权数据元素中以修改它包含的元素的关键性,否则认证必须失败。授权数据旨在限制票证的使用。如果服务无法确定限制是否适用于该服务,那么如果票证可用于该服务,则可能导致安全弱点。可选的授权元素可以封装在 AD-IF-RELEVANT 元素中。
在接下来的定义中,元素的 ad-type 值将被指定为小节号的最低有效部分,ad-data 的值将如 ASN.1 结构中所示,该结构遵循小节标题。
| ad-data 的内容 | ad-type |
|---|---|
| AD-IF-RELEVANT 的 DER 编码 | 1 |
| AD-KDCIssued 的 DER 编码 | 4 |
| AD-AND-OR 的 DER 编码 | 5 |
| AD-MANDATORY-FOR-KDC 的 DER 编码 | 8 |
5.2.6.1. IF-RELEVANT
AD-IF-RELEVANT ::= AuthorizationData
封装在 if-relevant 元素中的 AD 元素仅供理解嵌入元素的特定 ad-type 的应用服务器解释。不理解 if-relevant 元素中嵌入的元素类型的应用服务器可以忽略不可解释的元素。此元素促进了可能具有授权本地扩展的实现之间的互操作性。AD-IF-RELEVANT 的 ad-type 是 (1)。
5.2.6.2. KDCIssued
AD-KDCIssued ::= SEQUENCE {
ad-checksum [0] Checksum,
i-realm [1] Realm OPTIONAL,
i-sname [2] PrincipalName OPTIONAL,
elements [3] AuthorizationData
}
ad-checksum
使用会话密钥对 "elements" 字段中 AuthorizationData 的 DER 编码计算的加密校验和。其 checksumtype 是会话密钥的加密类型的强制校验和类型,其密钥使用值为 19。
i-realm, i-sname
如果与 KDC 本身的名称不同,则为发布主体的名称。当 KDC 可以验证由发布主体签名的元素的真实性时,将使用此字段,它允许此 KDC 通知应用服务器这些元素的有效性。
elements
由 KDC 发布的授权数据元素序列。
KDC 发布的 ad-data 字段旨在为 Kerberos 主体凭据提供一种在其自身内嵌入特权属性和其他积极授权机制的方法,扩大主体的特权,超出使用没有此类 a-data 元素的凭据所能做的。
如果没有此元素,则无法提供上述方法,因为 authorization-data 字段的定义允许 TGT 的持有者在请求服务票证时随意添加元素,并且还可以通过将元素包含在认证器中来将元素添加到委托票证中。
对于 KDC 发布的元素,这是可以防止的,因为元素由 KDC 签名,方法是使用服务器的密钥 (用于加密票证的相同密钥或从该密钥派生的密钥) 加密包含校验和。如果此 "签名" 不存在,应用服务器必须忽略封装在 KDC 发布的元素中的元素。此外,来自 TGT 的封装在此元素中的元素可以由 KDC 解释,并根据策略用作在派生票证中包含新签名元素的基础,但它们不会直接复制到派生票证。如果它们由不知道此元素的 KDC 直接复制到派生票证,则签名对于应用票证元素将不正确,应用服务器将忽略该字段。
不实现此元素的应用程序、应用服务器和 KDC 可以安全地忽略此元素及其封装的元素。
AD-KDC-ISSUED 的 ad-type 是 (4)。
5.2.6.3. AND-OR
AD-AND-OR ::= SEQUENCE {
condition-count [0] Int32,
elements [1] AuthorizationData
}
当限制性 AD 元素封装在 and-or 元素中时,当且仅当至少满足在 condition-count 中指定的封装元素数量时,才认为满足 and-or 元素。因此,通过将 condition-count 字段设置为 1 可以使用此元素来实现 "or" 操作,并且通过将条件计数设置为嵌入元素的数量可以指定 "and" 操作。不实现此元素的应用服务器必须拒绝包含此类型的授权数据元素的票证。
AD-AND-OR 的 ad-type 是 (5)。
5.2.6.4. MANDATORY-FOR-KDC
AD-MANDATORY-FOR-KDC ::= AuthorizationData
封装在 mandatory-for-kdc 元素中的 AD 元素将由 KDC 解释。不理解 mandatory-for-kdc 元素中嵌入的元素类型的 KDC 必须拒绝请求。
AD-MANDATORY-FOR-KDC 的 ad-type 是 (8)。
5.2.7. PA-DATA
从历史上看,PA-DATA 被称为 "预认证数据",这意味着它们用于增强与 KDC 的初始认证。从那时起,它们也被用作类型化孔,用于扩展与 KDC 的协议交换。
PA-DATA ::= SEQUENCE {
-- NOTE: first tag is [1], not [0]
padata-type [1] Int32,
padata-value [2] OCTET STRING -- might be encoded AP-REQ
}
padata-type
指示 padata-value 元素的解释方式。padata-type 的负值保留供未注册使用; 非负值用于元素类型的注册解释。
padata-value
通常包含另一种类型的 DER 编码; padata-type 字段标识此处编码的类型。
| padata-type | 名称 | padata-value 的内容 |
|---|---|---|
| 1 | pa-tgs-req | AP-REQ 的 DER 编码 |
| 2 | pa-enc-timestamp | PA-ENC-TIMESTAMP 的 DER 编码 |
| 3 | pa-pw-salt | salt (未经 ASN.1 编码) |
| 11 | pa-etype-info | ETYPE-INFO 的 DER 编码 |
| 19 | pa-etype-info2 | ETYPE-INFO2 的 DER 编码 |
此字段还可以包含 Kerberos 协议的某些扩展所需的信息。例如,它可能用于在返回任何响应之前最初验证客户端的身份。
padata 字段还可以包含帮助 KDC 或客户端选择生成或解密响应所需的密钥的信息。这种形式的 padata 对于支持某些令牌卡与 Kerberos 一起使用很有用。此类扩展的详细信息在单独的文档中指定。有关此字段的其他用途,请参阅 [Pat92]。
5.2.7.1. PA-TGS-REQ
在请求附加票证 (KRB_TGS_REQ) 的情况下,padata-value 将包含编码的 AP-REQ。认证器中的校验和 (必须是抗碰撞的) 将在 KDC-REQ-BODY 编码上计算。
5.2.7.2. 加密时间戳预认证
继续下一部分...
5.2.8. KerberosFlags
对于几种消息类型,使用特定的受约束位字符串类型 KerberosFlags。
KerberosFlags ::= BIT STRING (SIZE (32..MAX))
-- minimum number of bits shall be sent,
-- but no fewer than 32
兼容性注意: 以下段落描述了与 RFC 1510 对位字符串的描述相比的更改,在严格符合 ASN.1 DER 和 RFC 1510 的实现的情况下会导致不兼容。
ASN.1 位字符串有多种用途。位字符串的最简单用途是包含位向量,对各个位没有特定含义。此位向量不一定是八位的倍数。在 Kerberos 中使用位字符串作为紧凑布尔向量 (其中每个元素具有不同的含义) 会带来一些问题。紧凑布尔向量的自然表示法是 ASN.1 "NamedBit" 表示法,DER 要求使用 "NamedBit" 表示法的位字符串的编码排除任何尾随零位。这种截断很容易被忽略,特别是考虑到 C 语言实现自然选择将布尔向量存储为 32 位整数。
例如,如果 KDCOptions 的表示法包括 RFC 1510 中的 "NamedBit" 表示法,并且要编码的 KDCOptions 值仅设置了 "forwardable" (位号一) 位,则 DER 编码必须仅包含两位: 第一个保留位 ("reserved",位号零,值零) 和 "forwardable" 的值为一的位 (位号一)。
大多数现有的 Kerberos 实现在编码用作布尔向量的位字符串时无条件地在线路上发送 32 位。此行为违反了 RFC 1510 中用于标志值的 ASN.1 语法,但它发生在如此广泛安装的基础上,以至于协议描述正在被修改以适应它。
因此,本文档删除了各个位的 "NamedBit" 表示法,将它们降级为注释。KerberosFlags 类型上的大小约束要求始终编码至少 32 位,尽管宽松的实现可以选择接受少于 32 位并将缺失的位视为设置为零。
目前,KerberosFlags 的使用没有指定超过 32 位的标志,尽管本文档的未来修订版可能会这样做。当要在 KerberosFlags 值中传输超过 32 位时,本文档的未来修订版可能会指定应发送编码最高编号的值为一的位所需的最少位数。这在某种程度上类似于使用 "NamedBit" 表示法声明的位字符串的 DER 编码。
5.2.9. 与加密系统相关的类型
许多 Kerberos 协议消息包含 EncryptedData 作为任意加密数据的容器,该数据通常是另一种数据类型的加密编码。EncryptedData 中的字段帮助接收者选择用于解密封闭数据的密钥。
EncryptedData ::= SEQUENCE {
etype [0] Int32 -- EncryptionType --,
kvno [1] UInt32 OPTIONAL,
cipher [2] OCTET STRING -- ciphertext
}
etype
此字段标识使用哪种加密算法来加密 cipher。
kvno
此字段包含加密数据所使用密钥的版本号。它仅存在于使用长期密钥 (例如主体的密钥) 加密的消息中。
cipher
此字段包含加密文本,编码为 OCTET STRING。(请注意,[RFC3961] 中定义的加密机制必须包含完整性保护,因此不需要额外的校验和。)
EncryptionKey 类型是传输用于加密的加密密钥的方法。
EncryptionKey ::= SEQUENCE {
keytype [0] Int32 -- actually encryption type --,
keyvalue [1] OCTET STRING
}
keytype
此字段指定 keyvalue 字段中后面的加密密钥的加密类型。尽管其名称是 "keytype",但它实际上指定了加密类型。以前,允许以不同方式执行加密但能够使用具有相同特征的密钥的多个加密系统共享分配的号码来指定密钥类型; 此用法现已弃用。
keyvalue
此字段包含密钥本身,编码为八位字节字符串。
包含要认证的明文数据的消息通常会使用 Checksum 类型的成员来进行认证。Checksum 的大多数实例使用带密钥的哈希,尽管会注明例外情况。
Checksum ::= SEQUENCE {
cksumtype [0] Int32,
checksum [1] OCTET STRING
}
cksumtype
此字段指示用于生成随附校验和的算法。
checksum
此字段包含校验和本身,编码为八位字节字符串。
有关 Kerberos 中加密和校验和使用的简要说明,请参见第 4 节。