7.10 Key分发系统

为了建立跨服务器、跨项目、跨组织机构的信任关系,Limax集成Key分发系统,在PKIX框架的基础上,实现安全可靠的Key分发。获得的Key可以用来签名,加密,确保信任系统间安全共享信息。


  • 7.10.1 设计原则

    • 基本原理

      • 1. 服务器维护一个定时生成的随机数masterKey的数组,使用timestamp索引。

      • 2. 客户端生成nonce,连同信任域名字group,发送给服务器。

      • 3. 服务器执行key = Hash(masterKey, nonce, group)。timestamp和key发还客户端。

      • 4. 客户端组合timestamp,nonce,group形成keyIdent。

      • 5. 客户端使用key签名或者加密消息,连同keyIdent发送给接收客户端。

      • 6. 接收客户端使用keyIdent向服务器请求对应的key,用来验证或者解密消息。


    • 信任关系设计

      • 1. 通过约定证书签署方式,建立信任关系。

      • 2. 用KDSName约定Key分发系统名,必须使用有效的域名。

      • 3. 服务器证书的Subject中的RDN CommonName指定了KDSName,其它RDN不作约定。

      • 4. 同一Key分发系统中的所有服务器证书必须由同一CA签署。

      • 5. 客户端证书的SubjectAltName中必须有一个DNS条目,指定KDSName。

      • 6. 客户端证书的SubjectAltName中可以有多个URI条目,指定group。

      • 7. 同一CA签名的具有相同KDSName, group的客户端证书, 在Key分发系统中相互信任。例如, 同一CA为系统A, B, C, 签署客户端证书, 使用相同KDSNAme, 其中A包含group G0, G1, B包含group G0, G1, C包含group G0。在G0内, A,B,C可以互相通讯,G1内A,B可以互相通讯。

      • 8. 签发客户端的CA不一定需要与签发服务器的CA相同。不同CA签署的具有相同KDSName,group的客户端证书没有信任关系(实现上生成Key的时候客户端证书Issuer同时参与HASH计算)。


    • 服务器设计要点

      • 1. 同一CA签署的具有同一KDSName的服务器证书,唯一决定了一个Key服务网络。

      • 2. 定期生成新的masterKey,为消息发送客户端分配key,老的masterKey保留一定时间,保证消息接收客户端能够用keyIdent还原之前的key。

      • 3. Key服务网络设计成基于DHT的P2P网络,masterKey数组在服务网络中分发。P2P方式下服务网络规模不受限制,最大限度保证系统健壮性。


    • 客户端设计要点

      • 1. nonce用当前时间生成,有机会cache服务器响应,最大限度降低服务器负荷,减少客户端阻塞的机会。

      • 2. nonce的生成精度可调, 可以在签署证书时直接约定, group使用URI表示, 利用URI中fragment部分。例如, G0#10s, 约定了使用group G0时, 以10s为单位生成nonce, 许可的单位为s, m, h, 分别为秒, 分, 小时, 如果不带单位, 默认为毫秒。fragment不存在或者解析失败使用系统默认参数, fragment不作为group一部分。

      • 3. 客户端发起请求前,预先根据自己的证书检查group合法性,避免增加不必要的网络开销。当然,这不妨碍服务器执行检查。


  • 7.10.2 服务器运营


    • 签署证书

      这样的签署的服务器证书约定了Key分发系统key.limax-project.org


    • 服务器配置(keyserver.xml)

      顶层KeyServer元素,8个属性

      location:服务器证书的location

      passphrase:location的私钥启用密码,实际运营时,不应该填写该属性,而应该在服务器启动时输入。

      trustsPath:信任证书路径, location中已经包含了派生该证书的ROOTCA, 如果要信任其它ROOTCA(或者当前ROOTCA即将过期,应该将新的ROOTCA放置在这里), 则需要配置trustsPath, trustsPath可以是一个文件, 也可以是一个目录, 如果是目录, 遍历一层, 获取文件, 文件允许任何证书格式, 包括CER, DER, PKCS7, PKCS12, KeyStore, 从中获取ROOTCA,忽略所有错误。

      revocationCheckerOptions:服务器检测对方证书回收状态的选项,可选的值为DISABLE, NO_FALLBACK, ONLY_END_ENTITY, PREFER_CRLS, SOFT_FAIL, 大小写不敏感,后4个参数的解释见java.security.cert.PKIXRevocationChecker.Option,DISABLE具有最高优先级,如果配置了DISABLE,其它配置无意义。

      algorithm:指定了HASH算法,HASH算法决定了服务器返回客户端的Key长度,例如SHA1返回160位Key,SHA-256返回256位Key。

      master:指定了P2P网络的入口服务器列表,逗号分隔,可以是域名,可以是IP。

      keyLifespan:masterKey生存周期,单位为天,超出生存周期的masterKey被服务器删除。

      publishPeriod:masterKey发布周期,单位为天,一个新的周期开始时,服务器向网络中发布一个新的masterKey。没有配置该属性的服务器,不参与发布。理论上,一个服务网络内部只能有一个发布者,现实中可以配置多个保证冗余性,详见高级话题。


    • 服务器运行


      java –jar limax.jar keyserver [path to keyserver.xml]
      

      keyserver.xml目录下会生成一个keyserver.dht文件,该文件定时更新,保存了P2P网络中DHT邻居信息,有助于重启服务器时,快速建立邻居关系,不要删除。


  • 7.10.3 客户端开发


    • 签署证书

      这样签署的客户端证书约定了客户端使用Key分发系统key.limax-project.org,具有两个分组prjA和prjB,其中prjA使用10秒的nonce生成精度。


    • 编程接口

      • 1. limax.key.KeyDesc,Key描述类,提供2个关键方法。

        • 1.1. byte[] getIdent();,获取Key标识。发送端将标识,合并到签名或者加密的消息中发送。接收端使用Key标识向服务器请求对应的Key。

        • 1.2. byte[] getKey(); 获取Key。发送端用Key签名或者加密消息,接收端使用Key验证或者解密。

      • 2. KeyException,使用KeyException.Type getType()返回相关异常。

        • 2.1. SubjectAltNameWithoutDNSName,证书签署错误,SubjectAltName中没有包含DNS类型条目。

        • 2.2. SubjectAltNameWithoutURI,证书签署错误,SubjectAltName中没有包含URI条目。

        • 2.3. MalformedKeyIdent,key标识解码异常,通常是传输过程中被篡改,消息不可信。

        • 2.4. UnsupportedURI,当前客户端证书不支持指定的group。

        • 2.5. ServerRekeyed, 服务器无法使用指定timestamp生成Key。通常是timestamp对应的masterKey过期了, 这种情况下, 信息获取方应该向发送方重新请求消息。

      • 3. limax.key.KeyAllocator,Key分配器类

        • 3.1. KeyAllocator(SSLContextAllocator sslContextAllocator), 使用sslContextAllocator构造一个Key分配器, cache容量1024。可能抛出异常类型SubjectAltNameWithoutDNSName, SubjectAltNameWithoutURI。

        • 3.2. KeyAllocator(SSLContextAllocator sslContextAllocator, int cacheCapacity), 使用sslContextAllocator构造一个Key分配器, 指定cache容量。可能抛出异常类型SubjectAltNameWithoutDNSName, SubjectAltNameWithoutURI。

        • 3.3. KeyDesc createKeyDesc(java.net.URI uri),信息发送方,请求一个KeyDesc,使用uri指定的group,uri的fragment部分被忽略。可能抛出异常类型UnsupportedURI。如果抛出KeyException之外的异常,通常是网络错误,可以重试。

        • 3.4. KeyDesc createKeyDesc(byte[] ident),信息接收方, 使用收到的Key标识, 请求KeyDesc。可能抛出异常类型MalformedKeyIdent, UnsupportedURI, ServerRekeyed。如果抛出KeyException之外的异常,通常是网络错误,可以重试。

        • 3.5. String getDNSName(),获取客户端证书中签署的DNSName。

        • 3.6. Map<URI,Long> getURIs(),获取客户端证书中签署的group信息,Map的Value为nonce精度,单位为毫秒。

        • 3.7. void setHost(java.lang.String httpsHost), 指定访问的Key服务网络中的部分Key服务器的域名或者IP地址, 如果没有使用该方法设置服务器地址, 则默认使用getDNSName()返回的域名。如果域名解析出多个IP地址, 这些IP地址被一一访问, 直到没有发生网络错误, 或者全部发生错误, 抛出网络异常。

        • 3.8. String getHost(),返回当前正在使用的Key服务器域名或者IP。

      • 4. 系统属性

        • 4.1. limax.key.KeyAllocator.DEFAULT_PRECISION,nonce精度,单位毫秒,默认3600000。

        • 4.2. limax.key.KeyAllocator.TIMEOUT,网络访问超时,单位毫秒,默认3000。


    • 应用实现要点

      • 1. 如果服务提供者提供了新的ROOTCA,通过SSLContextAllocator.addTrust加入。

      • 2. 根据服务提供者的建议决定是否需要SSLContextAllocator.setRecovationCheckerOptions。

      • 3. 根据服务提供者的提供的配置决定KeyAllocator.setHost。

      • 4. KeyAllocator.createKeyDesc,正确进行异常分类,KeyException类型属于不可恢复异常,可能需要检查证书配置,或者请求消息发送方重发。其它Exception属于超时之类的网络异常(这样的异常应该非常少, 详见高级话题), 应该优先考虑重试操作,唯一例外是证书过期导致连接被reset,需要确认日志中的“Certificate renew fail”警告。

      • 5. 应该为消息设计自己的expire机制,masterKey寿命仅仅应该理解为expire的最大值。


上一页 下一页