📄 rfc2367.txt
字号:
一些消息由操作系统产生指出需要那些动作,没必要响应用户的任何消息。这
样的消息不被所有的PF_KEY套接字接收。这些消息是特定的,因为它们发生在预期
的频率。同样,一个实现可能更希望限制从内核返回的消息,因为不是所有的PF_KEY
套接字在同样可信的守护进程中。
许多标准的BSD套接字调用在PF_KEY套接字中没有定义,包括:bind(), connect(),
socketpair(), accept(),getpeername(), getsockname(), ioctl(), and listen()。
1.5 共同的PF_KEY操作
将一个新的安全关联加入内核有两种基本途径。最简单的方法是从应用程序发
送一个包含所有安全关联信息的SADB_ADD消息至内核的密钥引擎。这种方法特别适
用于手工密钥管理,这对于IPsec和其它安全协议是必需的。
第二种方法是:应用程序首先使用SADB_GETSPI消息从内核请求一个安全参数
索引(SPI)值,然后发送一个包含安全关联数据的SADB_UPDATE消息消息。这种方
法适用于密钥管理守护进程,但SPI值需要先于全部安全关联数据获得(这样SPI值
能够指出密钥管理会话的对端)。
使用SADB_DELETE消息可以删除单个的安全关联;删除一类安全关联或者整个
内核的安全关联表用SADB_FLUSH消息。
可信的应用层进程(如routed(8)或者gated(8))可以用SADB_GET消息从内核
的密钥引擎获得一个安全关联(如RIP SA或者OSPF SA)。
内核或者应用层程序可以使用SADB_ACQUIRE消息请求一个某些应用层密钥管理
进程建立并通过SADB_REGISTER消息在内核登记的安全关联。这个ACQUIRE消息拥有
一个相关联的序列号。这个序列号必须在随后的SADB_GETSPI、SADB_UPDATE和SADB_ADD
消息中使用,目的是明了那一个请求获得了它的密钥素材。系列号(下面详述)类
似于一个远程调用的处理标识符。
当一个安全关联的“软件周期”或者“硬件周期”期满时,从内核发送SADB_EXPIRE
消息至密钥管理程序。密钥管理程序以收到的SADB_EXPIRE消息中的软件周期为提
示协商一个替代的安全关联,这样在内核使用之前替代的安全关联已准备好。
SADB_DUMP消息主要是为了PF_KEY实现程序的调试,并且不能用于平常的PF_KEY
操作。
1.6 PF_KEY和PF_ROUTE之间的区别
下面指出路由套接字和PF_KEY之间的区别。曾用路由套接字的程序员将会发现
两者之间的差别。
* PF_KEY消息错误通常在PF_KEY消息中返回,代替说明write()错误的错误号。这
意味着其它PF_KEY套接字监听者可以知道别的进程的请求失败,这可用于审计。
这也意味着读PF_KEY消息错误不能做错误检查。
具体实现可以返回write()操作失败导致的EINVAL、ENOMEM和ENOBUFS错误,也可
以返回错误号。这是最佳处理对于普通错误,这样可以不被其它进程检测到并接
收错误。应用程序不能依赖于write()调用设置的错误,但是应该检查这些错误,
并用适当的方式处理。
* 全部消息不是总是有返回消息。SADB_ADD消息就是一个例子。
* PID不是由内核设定。发起消息的进程必须把sadb_msg_pid设置成自己的PID。如
果内核发起一个消息,sadb_msg_pid必须设置为0。源消息的应答应该有源消息的
PID(如:内核对SADB_ADD的响应,PID应设置成源SADB_ADD消息的PID值)。
1.7 名称空间
全部PF_KEYv2预定义和结构定义在头文件<net/pfkeyv2.h>中说明,有一个例
外:“PF_KEY”(如果包括“AF_KEY”有两个)在头文件<sys/socket.h>中说明。
所有的PF_KEYv2预定义以前缀“SADB_”开始,所有的结构名以“sadb_”开始,有
两个例外:“PF_KEY_V2”和“PFKEYV2_REVISION”。
“PFKEYV2_REVISION”是一个日期编码值就像由POSIX和X/Open定义的固定
值,当前值是199806L,1998是年,06是月份。
本文档没有描述的符号或结构没有作者的明确许可,在<net/pfkeyv2.h>中的
定义不能使用PF_KEYv2的命名空间,任何本规范没有描述的使用PF_KEYv2名称空间
的符号或结构必须以“SADB_X_”或“sadb_x_”开始。一个未能遵从这些规则的实
现是不适应本规范的并且不能有什么要求。这些规则也适用于任何可能包含
<net/pfkeyv2.h>
的文件。这个规定可以保证实现者不会遇到定义冲突。
1.8 手工密钥
与4.4-Lite BSD的PF_ROUTE套接口相同,本接口允许一个程序从头到尾完全支
配内核中的安全关联来实现PF_KEY。PF_KEY的实现必须具有一些手工接口,能提供
这里描述的PF_KEY接口的所有功能。
2. PF_KEY消息格式
PF_KEY消息由一个基本的消息头和一些可选的附加数据段组成,附加的数据段
格式由消息类型决定。
PF_KEY消息目前不要求任何具体非网络的多字节数据段的顺序。除非其它指定
(如SPI)数据段必须是主机字节序。
2.1 基本消息头格式
PF_KEY消息由基本消息头和随后的安全关联的具体数据组成,数据段的类型和
长度由统一的类型长度编码指定。
基本消息头使用POSIX类型,格式如下。为了直观,各字段对齐排列。
struct sadb_msg {
uint8_t sadb_msg_version;
uint8_t sadb_msg_type;
uint8_t sadb_msg_errno;
uint8_t sadb_msg_satype;
uint16_t sadb_msg_len;
uint16_t sadb_msg_reserved;
uint32_t sadb_msg_seq;
uint32_t sadb_msg_pid;
};
/* sizeof(struct sadb_msg) == 16 */
sadb_msg_version
PF_KEY消息的版本号,必须设置为PF_KEY_V2。否则,write()调
用将失败并报参数错误(EINVAL)。另外,应用程序不能理解从
内核收到的消息的格式,运行状态将无法确定。
sadb_msg_type 标识消息的类型。有效的消息类型稍后说明。
sadb_msg_errno 消息的发送者应设置此项为零。如果出现错误,消息的应答者在
此存放错误码。包括应用层的消息应答(如:应用层协商失败,
将返回错误号)。
sadb_msg_satype 标识安全关联的类型。有效的安全关联类型在<net/pfkeyv2.h>
中定义。本文档稍后列举目前的安全关联类型。
sadb_msg_len 包含消息的整个长度,64位字对齐,包括基本头长度和附加数据,
并包括可能存在的任何填充和额外空间。除非其它情况,所有其
它长度字段也是64位字对齐。
用户到内核的消息,这一项必须检验。如果检验失败必须返回错
误EMSGSIZE。内核到用户的消息,大小不匹配就像用户未提供足
够的缓存。在这种情况下,用户程序可以丢弃这个消息,但是应
努力析取超出的数据。
sadb_msg_reserved
保留值。消息发送者必须设置为零。本文档中所有的保留值含义
与此相同。
sadb_msg_seq 包含消息的序列号。这一项必须连同sadb_msg_pid唯一确定一个
进程的请求。发送者负责设置这一项并负责匹配一个请求的
sadb_msg_seq
(如:SADB_ACQUIRE)。
这一项就像一个同远端程序调用实现的交易ID
sadb_msg_pid 识别消息的发起进程或者消息的目的进程。例如:如果ID未2112
的进程发送一个SADB_UPDATE消息至内核,必须设置本项为2112,
并且内核在自己的应答消息中设置本项为2112。本项连同
sadb_msg_seq
能够唯一确定一个进程的请求。
通常用一个32位值保存操作系统的进程ID。
2.2 消息头位对齐和扩展头
基本的消息头长度是64位的倍数,如果头是64位对齐紧随其后在内存中的数据
也是64位对齐。一些随后的扩展头具有64位域,结果需要64位值的环境中进行对齐。
PF_KEY版本2的算法和长度的基本单位是64比特。所以:
* 所有的扩展头,包括sadb_ext覆盖域,必须是64比特的整数倍。
* 所有可变的数据长度必须适当填充,从而使消息长度是64比特的整数倍。
* 所有的长度字段,除非特别指定,以64比特为单位。
* 执行程序可以安全的以8和64比特为单位直接存取消息而没有定位错误的风险。
所有PF_KEYv2结构封装并且已经有意进行填充。具体实现不能往本文档定义的
结构中插入任何额外字段,包括隐藏的填充。并且禁止未改变扩展头类型就“扩展”
和“增强”已存在的结构头。本文档所定义的每一个结构已标明字节大小,防备无
声明的填充。具体实现中的结构必须符合所列出的结构大小。
2.3 附加的消息域
基本消息头后的附加数据由一系列长度-类型值字段组成。开始的32比特固定
格式如下:
struct sadb_ext {
uint16_t sadb_ext_len;
uint16_t sadb_ext_type;
};
/* sizeof(struct sadb_ext) == 4 */
sadb_ext_len 扩展头64位字对齐的长度。
sadb_ext_type 扩展头类型。具体值稍后详述,零为保留值。
扩展头的类型包括:安全关联、生存期、地址、密钥、身份、敏感度、提议和
支持项。一个消息中必须只能有一个扩展类型的实例(例如:基本头、密钥、生存
期,密钥是禁止的)。如果一个消息中有两个扩展类型将返回EINVAL错误。具体实
现可以给“扩展头值”一节介绍的扩展项排序。
如果遇到一个未知的扩展类型,必须忽略该扩展项。应用程序使用本文档未说
明的扩展头必须有其它的系统组件不做处理的准备。同样,如果应用程序遇到一个
从内核来的未知扩展,必须有能力正常运转。而且内核产生额外的扩展头类型不能
指望应用程序也能理解额外的扩展头类型。
所有的扩展项定义包括两个字段(长度和类型),因为它们代表一类扩展(就
像sockaddr_in和sockaddr_in6代表一类套接字地址)。在一个消息中sadb_ext头
最少含有4字节的扩展头数据,只有4字节也没问题。
在一个PF_KEY具体实现中,本节所列的扩展项必须全部实现。
2.3.1 安全关联扩展项
安全关联扩展项说明了单个安全关联的详细数据。当传递的是控制消息(例如
SADB_FLUSH或SADB_REGISTER)中没有这个扩展项,并且SADB_ACQUIRE消息中也没有。
struct sadb_sa {
uint16_t sadb_sa_len;
uint16_t sadb_sa_exttype;
uint32_t sadb_sa_spi;
uint8_t sadb_sa_replay;
uint8_t sadb_sa_state;
uint8_t sadb_sa_auth;
uint8_t sadb_sa_encrypt;
uint32_t sadb_sa_flags;
};
/* sizeof(struct sadb_sa) == 16 */
sadb_sa_spi 安全关联的安全参数索引。尽管是一个32位的字段,某些类型的
安全关联的SPI或密钥标识长度可能少于32位。在这种情况下,将
存储有意义的位,不需要的位清零。本字段必须是网络字节序。
sadb_sa_replay 如果不为零表示重放窗口大小,如果为零表示没有重放窗口在使
用。
sadb_sa_state 安全关联状态。稍后详述。
sadb_sa_auth 安全关联将要使用的认证算法。有效的认证算法稍后详述。如果
为零表示不使用认证算法。
sadb_sa_encrypt 安全关联将要使用的加密算法。有效的加密算法稍后详述。如果
为零表示不使用加密算法。
sadb_sa_flags 按位操作的安全关联选项。稍后详述。
内核必须检查这些值的正确性。例如:IPsec AH没有认证算法可能是一个错误。
在一些消息中,安全关联扩展项的一些字段的值应当忽略。
2.3.2 生存期扩展项
生存期扩展项说明了安全关联的一个或多个生存周期变量。如果生存期扩展项
不存在,则安全关联是永久有效的。安全关联应具有某种生存期,生存期分三种:
HARD指硬件限定期满;SOFT指软件限定期满;CURRENT指特定的安全关联的当前状
态。生存期扩展项的结构如下:
struct sadb_lifetime {
uint16_t sadb_lifetime_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -