美食网站的建设目的,食品饮料网站建设,盐城市城乡建设局网站教育培训栏目,怎样做一个网站赚钱吗随着IP安全体系结构#xff08;IPsec#xff09;的引入#xff0c;密钥加密和认证密钥的管理越来越需要一套标准机制。RFC 2367介绍了一个通用密钥管理API#xff0c;可用于IPsec和其他网络安全服务#xff0c;该API创建了一个新协议族#xff0c;即PF_KEY域#xff0c;…随着IP安全体系结构IPsec的引入密钥加密和认证密钥的管理越来越需要一套标准机制。RFC 2367介绍了一个通用密钥管理API可用于IPsec和其他网络安全服务该API创建了一个新协议族即PF_KEY域这这个密钥管理域中只支持原始套接字。
在大多系统上常值AF_KEY被定义成与PF_KEY有相同的值但RFC 2367明确密钥管理套接字必须用PF_KEY常值。
打开原始密钥管理套接字需要权限在权限按需分割的系统上对于打开密钥管理套接字这样的操作会有一个单独的权限在普通Unix系统上密钥管理套接字只有超级用户能打开。
IPsec基于安全关联SASecurity Association为分组提供安全服务。SA描述了源地址与目的地址加上可选的传输协议和端口、机制如认证、密钥素材的组合。一个流上可以有多个SA如一个用于认证、一个用于加密。存放在系统中的所有SA构成的集合称为安全关联数据库SADBSecurity Association DataBase。
一个系统的SADB可能用于IPsec以外的场合如OSPFv2、RIPv2、RSVP、Mobile-IP等在SADB中也可能有各自的表项。因此PF_KEY套接字不仅限IPsec使用。
IPsec还需要一个安全策略数据库SPDBSecurity Policy DataBaseSPDB描述分组流通的需求如主机A和主机B之间的分组流通必须通过IPsec AH认证未经认证的一律丢弃。SADB描述如何执行所需的安全步骤如主机A和主机B之间的分组流通按照策略在使用IPsec AHSADB就含有所用的算法和密钥。但SPDB没有标准的维护机制尽管PF_KEY可以维护SADB但对SPDB无能为力。KAME的IPsec实现使用PF_KEY的扩展来维护SPDB但它没有标准可循。
密钥管理套接字上支持3种操作 1.通过写到密钥管理套接字进程可以往内核和打开着密钥管理套接字的其他进程发消息。SADB表项的增加和删除也采用这种操作实现如OSPFv2等自行进行安全检查的进程也采用这种方式从某个密钥管理守护进程请求密钥。
2.通过读密钥管理套接字进程可以从内核或其他进程接收消息。内核可以采用这种操作请求某个密钥管理守护进程为依照策略需要受到保护的新TCP会话安装一个SA。
3.进程可以往内核发送一个倾泻dumping请求内核作为应答倾泻出当前SADB这是一个调试功能并非所有系统都可用。
所有密钥管理套接字的消息都有同样的首部每个消息后跟各种扩展取决于可提供的或所请求的信息。所有相关结构都定义在头文件net/pfkeyv2.h中。每个消息和扩展都是64位对齐的消息长度是8字节的整数倍所有长度字段都是64位的每个消息如果不足64位的整数倍必须填充到下一个64位边界填充字节的具体值没有定义。以下是密钥管理消息首部 sadb_msg_type成员的值确定密钥管理消息类型可选值如下 每个sadb_msg首部后跟零个或多个扩展大多消息类型都有必需和可选的扩展以下是所有扩展类型 进程使用SADB_DUMP消息倾泻当前SADB它是最简单的密钥管理消息不需要任何扩展单纯是16字节的sadb_msg首部。一个进程通过某个密钥管理套接字发送一个SADB_DUMP消息到内核后内核通过同一个套接字响应一系列SADB_DUMP消息每个消息对应一个SADB表项这个列表的末尾由成员sadb_msg_seq值为0来指示。
通过把SADB_DUMP请求消息的sadb_msg_satype成员设为下图中的某个值进程可限制返回的SA的类型若该成员的值为SADB_SATYPE_UNSPEC常值则SADB中所有SA都会返回 并非所有系统都支持所有SA类型KAME实现仅支持IPsec的两类SASADB_SATYPE_AH和SADB_SATYPE_ESP因此如果试图倾泻SADB_SATYPE_RIPV2类型的SA将返回EINVAL错误。如果SADB中没有所请求类型的SA将返回ENOENT错误。
以下是用于倾泻SADB的程序
void sadb_dump(int type) {int s;char buf[4096];struct sadb_msg msg;int goteof;// 需要特定系统权限因为它允许访问敏感的密钥素材s Socket(PF_KEY, SOCK_RAW, PF_KEY_V2);/* Build and write SADB_DUMP request */bzero(msg, sizeof(msg));// 调用socket时第三个参数为PF_KEY_V2因此此处的版本也设为该值msg.sadb_msg_version PF_KEY_V2;msg.sadb_msg_type SADB_DUMP;msg.sadb_msg_satype type;// sadb_msg_len的单位是8字节块msg.sadb_msg_len sizeof(msg) / 8;// 将sadb_msg_pid设置为自己的进程id// 从进程到内核的所有消息都要以发送者的PID来标识msg.sadb_msg_pid getpid();printf(Sending dump message:\n);// 使用我们的print_sadb_msg函数显示本消息// 我们不给出该冗长无味的函数的源码它以直观可读方式// 显示正写到或已读自密钥管理套接字的某个消息print_sadb_msg(msg, sizeof(msg));Write(s, msg, sizeof(msg));printf(\nMessages returned:\n);/* Read and print SADB_DUMP replies until done */goteof 0;while (goteof 0) {int msglen;struct sadb_msg *msgp;msglen Read(s, buf, sizeof(buf));msgp (struct sadb_msg *)buf;print_sadb_msg(msgp, msglen);if (msgp-sadb_msg_seq 0) {goteof 1;}}close(s);
}int main(int argc, char **argv) {int satype SADB_SATYPE_UNSPEC;int c;opterr 0; /* dont want getopt() writing to stderr */// POSIX的getopt函数的第三个参数指定允许出现的命令行选项字符// 本例中t字符后跟一个冒号表示这个选项需要一个参数// 如果该参数为Oi:l:v则表明程序接受4个选项// i和l需要参数O和v不需要参数// getopt函数与在unistd.h头文件中定义的一下4个全局变量协同工作// extern char *optarg;// extern int optind, opterr, optopt;// 在调用getopt前把opterr设为0表示发生命令行参数与第3个参数不// 匹配等错误时该函数不把出错消息写到标准错误因为我们想自行处理错误// POSIX声称第3个参数以“:”打头也能阻止函数写出到标准错误但有些实现不支持while ((c getopt(argc, argv, t:)) ! -1) {switch (c) {case t:// 使用我们的getsatypebyname函数从文本串得到类型值// 用于指定倾泻指定的SA类型if ((satype getsatypebyname(optarg)) -1) {err_quit(invalid -t option %s, optarg);}break;default:err_quit(unrecognized option: %c, c);}}sadb_dump(satype);
}在一个具有2个静态SA预先配置和固定的安全关联的系统上运行本倾泻程序的输出 向SADB增加一个SA最直接的方法是手动填写所有参数并发送一个SADB_ADD消息。虽然手动指定密钥素材会导致不易更改密钥易于更改密钥对避免密码分析攻击很重要但配置起来很容易Alice和Bob使用带外数据达成一个密钥和算法然后使用它们。
SADB_ADD消息必需的扩展有3种SA、地址和、密钥可选的扩展也有3种生命期、身份、敏感性。
SA扩展由sadb_sa结构描述 sadb_sa_spi成员含有安全参数索引SPISecurity Parameters IndexSPI结合目的地址、所用协议如IPsec AH唯一标识一个SA。接收分组时SPI用于查找该分组的SA发送分组时SPI插入到分组中供对端使用。SPI没有别的含义因此其值可以顺序地或随机地分配也可使用目的系统想使用的方法进行分配。sadb_sa_replay指定反重放窗口的大小。sadb_sa_state成员值在动态创建的SA的生命周期内会发生变化可取值如下 手动创建的SA总是处于SADB_SASTATE_MATURE状态。
sadb_sa_auth成员和sadb_sa_encrypt成员本别指定本SA的认证算法和加密算法可取值如下 sadb_sa_flags成员目前只定义了一个标志即SADB_SAFLAGS_PFS该标志要求完备前向安全PFSperfect forward security即密钥的值不依赖于先前的密钥或某个主密钥PFS确保即使长期的私钥泄露先前的通信内容也无法被解密在传统的加密协议中使用的是长期有效的密钥如果这些密钥被泄露攻击者可以将其用于解密先前截获的通信数据而PFS使用的是临时生成的一次性密钥这些密钥仅用于加密和解密单个会话或通信。该标志值用于从密钥管理守护进程请求密钥的场合增加静态SA时不用。
除了以上SA扩展外SADB_ADD消息的另一种必需的扩展是地址扩展。由常值SADB_EXT_ADDRESS_SRC和SADB_EXT_ADDRESS_DST指定的是源地址和目的地址这两个地址是必需的而常值SADB_EXT_ADDRESS_PROXY指定的是代理地址代理地址是可选的。代理地址详细信息可见RFC 2367。地址扩展使用以下sadb_address结构 sadb_address结构中的sadb_address_exttype成员确定本地址是源地址、目的地址还是代理地址。sadb_address_proto成员指定本SA匹配的协议若为0则匹配所有协议。sadb_address_prefixlen成员给出sadb_address结构表示的地址的有效位数如IPv4是32位。sadb_address结构后跟匹配地址族的sockaddr结构如sockaddr_in或sockaddr_in6。sockaddr中的端口仅在sadb_address_proto指定的协议支持端口号的前提下如IPPROTO_TCP才有效。
SADB_ADD消息的最后一种必需的扩展是认证和加密密钥分别由SADB_EXT_KEY_AUTH和SADB_EXT_KEY_ENCRYPT指定由sadb_ley结构描述 sadb_key_exttype成员定义本密钥是认证密钥还是加密密钥。sadb_key_bits成员指定本密钥的位数。密钥本身紧跟在sadb_key结构后。
增加一个静态SADB表项的代码
void sadb_add(struct sockaddr *src, struct sockaddr *dst, int type, int alg,int spi, int keybits, unsigned char *keydata) {int s;char buf[4096], *p; /* XXX */struct sadb_msg *msg;struct sadb_sa *saext;struct sadb_address *addrext;struct sadb_key *keyext;int len;int mypid;s Socket(PF_KEY, SOCK_RAW, PF_KEY_V2);mypid getpid();/* Build and write SADB_ADD request */// 构造SADB_ADD消息首部bzero(buf, sizeof(buf));p buf;msg (struct sadb_msg *)p;msg-sadb_msg_version PF_KEY_V2;msg-sadb_msg_type SADB_ADD;msg-sadb_msg_satype type;msg-sadb_msg_pid getpid();len sizeof(*msg);p sizeof(*msg);// 添加必需的SA扩展saext (struct sadb_sa *)p;saext-sadb_sa_len sizeof(*saext) / 8;saext-sadb_sa_exttype SADB_EXT_SA;saext-sadb_sa_spi htonl(spi); // 必须以网络字节序存放// 关闭重放保护saext-sadb_sa_replay 0; /* no replay protection with static keys */saext-sadb_sa_state SADB_SASTATE_MATURE;// 设置认证算法saext-sadb_sa_auth alg;// 设置加密算法saext-sadb_sa_encrypt SADB_EALG_NONE;saext-sadb_sa_flags 0;len saext-sadb_sa_len * 8;p saext-sadb_sa_len * 8;// 将源地址以SADB_EXT_ADDRESS_SRC扩展形式添加到本消息addrext (struct sadb_address *)p;// 长度字段先加7再除8是按64位边界填充后的长度addrext-sadb_address_len (sizeof(*addrext) salen(src) 7) / 8;addrext-sadb_address_exttype SADB_EXT_ADDRESS_SRC;// 本SA适用于所有协议addrest-sadb_address_proty 0; /* any protocol */// 设置地址长度IPv4为32位IPv6为128位addrext-sadb_address_prefixlen prefix_all(src);addrext-sadb_address_reserved 0;memcpy(addrext 1, src, salen(src));len addrext-sadb_address_len * 8;p addrext-sadb_address_len * 8;// 与源地址一样的方式将目的地址加入本消息// 但sadb_address_exttype为SADB_EXT_ADDRESS_DSTaddrext (struct sadb_address *)p;addrext-sadb_address_len (sizeof(*addrext) salen(dst) 7) / 8;addrext-sadb_address_exttype SADB_EXT_ADDRESS_DST;addrext-sadb_address_proto 0; /* any protocol */addrext-sadb_address_prefixlen prefix_all(dst);addrext-sadb_address_reserved 0;memcpy(addrext 1, dst, salen(dst));len addrext-sadb_address_len * 8;p addrext-sadb_address_len * 8;// 添加认证密钥keyext (struct sadb_key *)p;/* 7 handles alignment requirements */keyext-sadb_key_len (sizeof(*keyext) (keybits / 8) 7) / 8;keyext-sadb_key_exttype SADB_EXT_KEY_AUTH;keyext-sadb_key_bits keybits;keyext-sadb_key_reserved 0;// 把密钥数据复制到本扩展首部后面memcpy(keyext 1, keydata, keybits / 8);len keyext-sadb_key_len * 8;p keyext-sadb_ley_len * 8;msg-sadb_msg_len len / 8;printf(Sending add message:\n);print_sadb_msg(buf, len);Write(s, buf, len);printf(\nReply returned:\n);/* Read and print SADB_ADD reply, discarding any others */for (; ; ) {int msglen;struct sadb_msg *msgp;msglen Read(s, buf, sizeof(buf));msgp (struct sadb_msg *)buf;// 寻找pid与本进程一致的消息if (msgp-sadb_msg_pid mypid msgp-sadb_msg_type SADB_ADD) {print_sadb_msg(msgp, msglen);break;}}close(s);
}运行以上程序发送SADB_ADD消息为127.0.0.1和127.0.0.1之间的分组流通增设一个SA 上图中应答消息中没有给出密钥内容这是因为应答消息被发送到所有PF_KEY套接字但不同的套接字可能属于不同的保护域保护域是一种安全机制用于隔离和控制不同进程或实体之间的访问权限每个保护域都有自己的访问规则和权限设置密钥数据不应该跨越保护域这是为了防止密钥数据被未经授权的实体或进程访问、修改或泄露。把这个SA添加到SADB后我们对127.0.0.1执行ping命令使该SA真正被使用然后倾泻出SADB以检查所添加的SA 从倾泻的结果可见内核把我们的IP协议从0改为了255这是本实现的一个特性实际是一个缺陷而非PF_KEY套接字的普遍特性。此外内核把前缀长度由32改为了128另一个缺陷它看起来是由内核混淆IPv4和IPv6地址所引起。内核还返回了另一个我们的倾泻程序不认识的扩展编号19不认识的扩展我们的倾泻程序会根据它的长度字段跳过。内核还返回了生命期扩展含有本SA的当前生命期信息生命期扩展相关的结构如下 生命期扩展有3种SADB_LIFETIME_SOFT和SADB_LIFETIME_HARD这两个扩展分别指定一个SA的软生命期和硬生命期。当软生命期结束时内核发送一个SADB_EXPIRE消息当硬生命期结束后该SA不能再用。最后一种生命期扩展是SADB_LIFETIME_CURRENT扩展它用于指出相应SA的当前生命期它会在SADB_DUMP、SADB_EXPIRE、SADB_GET消息中返回。
周期性地重新产生密钥动态维护安全关联有助于进一步提高安全性这种操作通常由诸如IKE之类的协议执行。
为了获悉何时需要为一对主机提供新的SA密钥管理守护进程应预先用SADB_REGISTER请求消息向内核注册自身其中的sadb_msg_satype成员指出所能处理的SA类型。如果守护进程能处理多种SA类型它就为其中每个类型发送一个SADB_REGISTER请求消息。在SADB_REGISTER应答消息中内核提供一系列受支持算法扩展用来指出哪些加密和认证机制、哪些密钥长度得到支持。受支持算法扩展由sadb_supported结构描述 紧跟在每个sadb_supported结构相当于该扩展的首部后的是一系列以sadb_alg结构给出的加密或认证算法的描述。
sadb_supported扩展首部后的每个sadb_alg结构代表系统支持的一个算法下图是为处理SA类型SADB_SATYPE_ESP 而发出的SADB_REGISTER请求的一个可能应答 以下程序使用SADB_REGISTER请求向内核注册自身进程然后显示内核在应答中返回的受支持算法列表
void sadb_register(int type) {int s;char buf[4096]; /* XXX */struct sadb_msg msg;int goteof;int mypid;s Socket(PF_KEY, SOCK_RAW, PF_KEY_V2);mypid getpid();/* Build and write SADB_REGISTER request */bzero(msg, sizeof(msg));msg.sadb_msg_version PF_KEY_V2;msg.sadb_msg_type SADB_REGISTER;msg.sadb_msg_satype type;msg.sadb_msg_len sizeof(msg) / 8;msg.sadb_msg_pid mypid;printf(Sending register message:\n);print_sadb_msg(msg, sizeof(msg));Write(s, msg, sizeof(msg));// SADB_REGISTER请求消息不需要任何扩展printf(\nReply returned:\n);/* Read and print SADB_REGISTER reply, discarding any others */for (; ; ) {int msglen;struct sadb_msg *msgp;msglen Read(s, buf, sizeof(buf));msgp (struct sadb_msg *)buf;// 应答消息中的pid是本进程的pid且类型为SADB_REGISTERif (msgp-sadb_msg_pid mypid msgp-sadb_msg_type SADB_REGISTER) {print_sadb_msg(msgp, msglen);break;}}close(s);
}在一个不仅仅支持RFC 2367中规定协议的系统上运行以上register程序 当内核需要与某个目的地址通信时如果根据策略该单向分组流必须经由一个SA而内核没有可用SA时内核就向注册了所需SA类型的密钥管理套接字发送一个SADB_ACQUIRE消息其中含有一个描述内核所提议算法及密钥长度的提议扩展该提议可能综合了系统支持的配置与限制该单向分组流的预配置策略。提议内容是一个由算法、密钥长度、生命期所构成的按照优先顺序排列的列表。当一个密钥管理守护进程收到一个SADB_ACQUIRE消息后它执行必要的操作以选择一个内核提议的密钥再把该密钥安装到内核中。密钥管理守护进程使用SADB_GETSPI消息请求内核从一个期望的范围内选择一个SPI内核对于该SADB_GETSPI消息的响应还包括建立一个处于larval幼虫状态的SA然后守护进程使用由内核提供的SPI与远端协商安全参数接着使用SADB_UPDAE更新该SA使它进入mature成熟状态。动态创建的SA通常含有关联的软生命期和硬生命期任何一个生命期结束时内核将发送一个SADB_EXPIRE消息其中指出期满的是软生命期还是硬生命期如果软生命期结束SA就进入dying垂死状态期间它仍可使用但内核应该为它获取一个新SA如果硬生命期结束去SA就进入dead死亡状态这种状态的SA不能继续使用必须从SADB中删除。
密钥管理套接字用于在内核、密钥管理守护进程、诸如路由守护进程等安全相关的消费进程间交换SA。SA既可以手工静态安装也可以使用密钥协商协议自动动态安装。动态密钥有关联的生命期当软生命期结束时密钥守护进程得到通知这样的SA如果在硬生命期结束前未被新SA替换那就不能再使用。
进程和内核通过密钥管理套接字交换的信息共有10种类型每种消息类型都有关联的扩展有的扩展是必需的有的是可选的。每个由进程发送的消息的应答被内核发送到所有打开着的密钥管理套接字但其中含有敏感数据的扩展都会被抹除。