OSGi规范中文版(第5版 core R5.0.0)-第2章安全层(Security Layer)[译]

译者:陈旭东  原文: http://www.osgi.org/Specifications/HomePage

 2.1 介绍

        OSGi安全层是一个可选层,也是构成OSGi framework的基础,并且OSGi安全层基于Java2 security架构。另外这个层提供了部署应用和管理应用的基础架构,而这些应用在执行环境中必须受到严格控制。


2.1.1要点

  • 细粒度-运行在OSGi Framework下的应用必须有细粒度的控制。
  • 可管理-安全层本身不提供应用控制API,而是由生命周期层(Life Cycle层)来代理管理API。
  • 可选-安全层是可选的。


2.2 安全层概述

        Framework安全层模型基于Java2规范。如果执行安全检测,则必须由Java 2 Security架构([3]Java 2 Security Architecture)来操作,而且此规范假定读者已经熟悉了Java 2 Security。可选情况在2.2.2中详细描述


2.2.1代码认证

    OSGi framework能够通过以下方式认证代码:

  • 位置认证
  • 签名认证

    在更高层次上,还定义了管理认证代码单元的授权服务:

  • 权限管理服务-基于全路径字符串的权限管理
  • 条件权限管理服务-基于条件模型管理权限,能够检测位置和签名。

    Jar文件都会有数字签名,详细描述见2.3 Jar文件的数字签名。


2.2.2 安全可选情况

        Framework在Java平台上运行,必须提供Java2权限所需的Java Security API,而平台资源受限,这些Java Security API可能只是空实现,因此当Bundle加载或者执行这些API时,也不一定有安全检测。允许空实现的API如下:

  • checkPermission–返回时不抛出SecurityException异常.
  • checkGuard–返回时不抛出SecurityException异常.
  • implies– Returntrue.

2.3 Jar文件的数字签名

        在这一节中详细定义了Jar文件如何被数字签名。由于Java不同版本有不一样的Java规范,而且在这些规范中有很多可选或者不明确的定义,故本节也只定义了其中重要的一部分。

    数字签名其实是一个安全特性,特征如下:

  • 验证签名者
  • 确保签名后的内容没有被修改

    在OSGi framework中,对jar文件的签名会关联着这个jar,这些联系会用于:

  • 在认证的基础上授权给jar文件
  • 通过对bundle权限操作来选定这些bundle

     例如:操作员在他们设备上赋予使用ACME公司网络的权限,这时如果带有ACME公司签名的bundle部署在操作员设备上,就能使得这些bundle使用ACME公司网络了。同理,能授权一个特定的bundle,只管理带有ACME公司签名的bundle生命周期。

其实签名提供了一种强大的代理模型。它允许操作员赋予一个公司一系列受限的权限,之后这个公司就可以创建JAR文件来使用这些权限了,而且不需要进行任何额外的干预或者通讯。 这种代理模型描述如下图2.1所示:

alt

2.1代理模型

​        数字签名基于公钥加密机制。公钥加密机制使用2个有关联的数字作为key,其中一个key为公钥,另外一个key为私钥。公钥是共享的、可被自由传播,而私钥必须要保密。

用私钥加密的消息只能通过公钥才能被正确的验证。这可以用来验证消息的签名者身份(这里假设公钥是可信的,具体细节将在2.3.5证书一节讨论)。

        数字签名的处理过程基于Java 2的Jar文件签名。处理数字签名的过程是重复、受限的,而且这个处理过程得到了强化,其目的是为了提高OSGi bundle的互操作性。


2.3.1 JAR文件结构和Manifest

        一个Jar文件可以有多个签名信息。每份签名信息必须在Jar文件中存储2条资源信息:

  • 签名指令资源文件:和Manifest有相似的结构,采用.SF后缀,这个文件提供了完整的manifest文件摘要。
  • PKCS#7资源文件:包含对签名指令文件的数字签名信息。具体参考[11] Public Key Cryptography Standard #7(公钥密码标准)

        这些Jar文件的签名资源必须放在META-INF目录下,另外在META-INF目录下的文件采用非常规方法签名。

        在jar文件流中,签名资源文件必须跟随在Manifest.mf文件之后、其他资源文件之前。如果不这么做,framework将不会接受签名信息,并且认为bundle是没有被签名的。文件的排列顺序非常重要,这是因为接受Jar文件的方式是文件流而不是缓存区读取,而且在其他资源加载之前,需要加载所有安全信息。这个模型如图2.2

alt

图2.2 JAR中的签名文件

        签名指令资源文件包含了manifest资源的摘要信息,这些信息并不是实际的数据。这些摘要信息只是一种对资源文件字节计算的结果,通过这种方式,很难再创建具有相同摘要信息的字节。

        ​JarManifest必须包含一个或者多个实际资源的摘要信息,而且在manifest中存放的是以摘要信息为名称的列表,摘要名称的标记是算法描述加上“-Digest”,例如:SHA1-DigestOSGi Framework推荐下面几种摘要算法。

  • MD5– Message Digest 5,在MD4的基础上改进而来,用来生成128位的哈希值,在参考文献[7]RFC 1321 The MD5 Message-Digest Algorithm.有详细描述
  • SHA1-SHA的一种改进算法,用来生成160位的哈希值,在参考文献有定义:[6]Secure Hash Algorithm 1

哈希值必须采用Base64编码,关于Base64编码定义可以参考参考文献[8] RFC 1421 Privacy Enhancement for Internet Electronic Mail.

例如,下面是一个Manifest例子:

Manifest-Version: 1.0

Bundle-Name: DisplayManifest


Name: x/A.class

SHA1-Digest: RJpDp+igoJ1kxs8CSFeDtMbMq78=


Name: x/B.class

SHA1-Digest: 3EuIPcx414w2QfFSXSZEBfLgKYA=


alt

 2.3 JAR文件的签名信息

​        OSGiJar必须对所有的资源文件进行签名,除了META-INF目录下的文件(默认的jar签名工具)。这需要遵守javajar签名标准,而且没有OSGi jar是部分签名的。OSGi规范只支持完整签名的Bundle,这样做是由于部分签名会破坏package的私有性,因为一个Bundle的所有代码使用了相同的保护域,这会简化安全API的处理。

​        在嵌套的Jar文件(如Bundle-ClassPath中的Jar)中签名文件会被忽略。这些嵌套Jar文件必须和包含它们的Bundle共享保护域。他们会认为资源文件是存储在外部的Jar文件中。

​        每份签名信息依据2份资源文件,第1个文件是签名指令文件,这个文件采用.SF后缀结尾。第2个文件的结构类似于Manifest文件,除了开头部分。开头如下:Signature-Version: 1.0 instead of Manifest-Version: 1.0

​        和签名文件关联的文件有Manifest资源中的摘要,header头使用算法名称(例如SHA1),后缀为-Digest-Manifest。例如:

Signature-Version: 1.0

SHA1-Digest-Manifest: RJpDp+igoJ1kxs8CSFeDtMbMq78=

MD5-Digest-Manifest: IIsI6HranRNHMY27SK8M5qMunR4=


        签名资源也可以包含多个片段,但是,这些片段是被忽略的。

​        如果签名资源有多个签名者,并且使用了同样的摘要算法,那么可以同时读取出来。但是,对于每一个签名者,必须有单独的签名指令文件,而且不允许在签名者之前共享签名指令文件。

        签名指令文件在图2.4中描述(签名者:ACME和DAFFY):

alt

图2.4 Jar中的Manifest,签名指令文件、摘要


2.3.2 Java Jar的文件约束

        OSGi Bundle是有效的Jar文件,但是对于Bundle来说还有一些其他的约束。

  • Bundle不支持部分签名,除了META-INF文件夹,在Manifest文件中必须包含对所有资源的描述。所有签名字段在META-INF中都会被验证,子文件夹也是。
  • 在签名文件中,名称部分会被忽略,只使用Manifest摘要。

2.3.3 有效签名

        Bundle能够通过多个签名者的签名。签名信息包含一对一的签名文件,这些签名文件以.SF后缀结尾。PKCS#7资源文件也有相同名字的签名文件但是使用RSA或者DSA后缀。

当一个签名符合下述条件时是有效的:

  • 签名文件包含入口资源文件META-INF/MANIFEST.MF
  • 完整的Manifest必须包含SHA1或者MD5摘要
  • 所有摘要必须匹配manifest
  • PCKS#7资源文件是有效签名(签名使用RSA或者DSA后缀),而且用于签名资源文件。

        完整的Bundle被有效的签名是必须的,也就是说,如果一个签名是无效的,那么整个Bundle就被视为无签名。


2.3.4 签名算法

        有几种不同的算法可以支持数字签名。OSGi Framework实现应该支持以下算法:

  • DSA- The Digital Signature Algorithm。这个标准定义在参考文献[9]DSA。这是美国政府的数字签名标准,以.DSA为后缀。
  • RSA-Rivest, Shamir and Adleman。公开密钥算法很流行,定义在参考文献[10]RSA。以.RSA作为后缀。
  • RSA和DSA签名文件的格式采用PCKS#7标准,定义在参考文献[11]Public Key Cryptography Standard #7。PKCS#7标准提供了利用算法加密信息进行验证的方法,验证算法使用公开密钥算法,公开密钥算法验证如下信息:
  • 数字签名匹配签名指令文件
  • 签名通过私钥创建与证书关联。

完整的签名结构参考图2.4


2.3.5 证书

         证书是签名文件的总称,包含名称和公钥信息,并且证书有多种格式。OSGi Jar签名基于X.509证书标准。

        这个标准已经形成多年,目前是OSI组织标准的一部分,X.509定义在参考文献[2]

X.509 Certificates

        X.509证书包含以下内容:

  • 标题名称-标题名称唯一标识证书所有者信息。例如:一个人可能拥有名字、国籍、email地址、组织、部门等信息,这个标识符是一个Distinguished Name(唯一标识名),Distinguished Name的定义在2.3.6
  • 认证机构名称-发出证书的认证机构名称是一个唯一标识名(Distinguished Name
  • 证书扩展-证书也可以包含图片、指纹编码信息、护照号码等其他信息
  • 公钥信息-公钥用于加密,而私钥用于解密。公钥可以自由发布,而私钥必须得保密。公钥信息置顶了加密的算法和公钥的标题。
  • 有效日期-证书只在特定时间内有效。
  • 认证机构数字签名-认证机构标识第1个元素增加证书可信度,接受证书可以对照签名来检查证书,如果接收者信任该机构,意味着信任签发证书的实体。

证书结构如图2.5

alt

图2.5证书结构


        证书能够被自由分发,并没有包含任何保密信息,因此,PKCS#7资源包含签名证书。表面上证书不能进行校验,因为证书包含在Bundle内部。入侵者可以轻易的创建自己的证书,而接收者只需要验证证书的发行者是否可信即可。无论如何在证书处于可信之前,证书必须被校验,因此有必要建立一个可信模型。

​        OSGi标准支持可信模型,但是不需要实现。证书放在一个库中,默认是可信的。然而,将证书放到一个库中,使得证书库过于庞大,特别是在一个开发模型中,一个设备拥有成千上万的证书,对于证书的管理是非常困难的。

​        解决方案是采用一个证书验证其他证书,通过多次迭代处理,形成一个证书链的方式。所有证书链上的证书都在PKCS#7文件中:如果一个证书可在可信证书库中找到,那么与这个证书相关的证书都是可信的,模型的尺度缩小到了一个合理状态,而且这样做只有很少一部分证书需要管理,这也是浏览器中所用到的证书模型,具体描述见图2.6

alt

2.6证书扇形展开

规范中没有描述如何对可信证书库进行存取,只是描述了证书库的组装和组织结构。

2.3.6 唯一标识名DNDistinguished Name

        X.509命名采用Distinguished Name(DN)。DN是一个高度结构化的名称,在一个层次化的命名空间对节点进行验证。DN概念来源于X.500目录服务,这种目录服务预想为时间范围的命名空间并且由PTTs管理。现在DN被用在由操作员设计的局部命名空间标识,例如:验证Bugs的DN名称如图2.7

alt

图2.7命名空间中的国籍、公司和个人

        名字空间是逆序遍历,开始部分是不重要的信息,但是却是具体的信息。因此,属性的排序是很重要的,2个具有相同属性但是排序不同的DN是不一样的。

​        在示例中,根节点搜索中有一个属性ccountryName国家)的值为US,然后搜索c节点中有一个属性o(organizationName组织名称)值为ACME,接着搜索o节点中有一个子节点属性为cn(commonName普通名称)值为Bugs Bunny

​        树模型在X.500标准的DN中有正式定义,但是实际上很多DN有很多和数据结构没有关系的属性,例如:很多DNou(organizationalUnit组织单元)节点还有批注和版权信息。

​        X.509证书中的DN名称用ASN.1(ISO定义的语言类型)二进制结构表达。但是,DN经常用于交互,有时,系统需要确认对一个证书的使用,或者操作员要根据客户证书对其赋予权限。因此,DN名称需要具有很好的可读性非常重要,而采用ASN.1方式的可读性比较差,本规范只用了在RFC 2253(具体定义看参考文献[1]RFC 2253Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names)中用在类javax.security.auth.x500.X500Principal中规定的范式来定义的DN字符串。

​        然而,由于使用一些不常用的类型和特征使得编码的复杂性提高(二进制数据、多值的RDN、多种语言字母、具有特殊匹配规则的属性)。框架的实现必须支持这些特性,但是用户应该避免这样做。因为这些特性现在已经很少使用了。

DN字符串格式如下:

dn ::= rdn ( ’,’ rdn ) *

rdn ::= attribute ( ’+’ attribute ) *

attribute ::= name ’=’ value

name ::= readable | oid

oid ::= number ( ’.’ number ) * //参考1.3.2

readable ::= <see attribute table>

value ::= <escaped string>


分割符前面和后面的空格是被忽略的,值中间有空格是有用的,值中间的多个空格认为是一个空格,值中间不允许出现通配符(’*’ \u002A)。下面的值必须用反斜杠进行转换(\u005C)

comma          ’,’      \u002C

plus            ’+’      \u002B

double quote     ’"’      \u0022

reverse solidus   ’\’      \u005C

less then        ’<’      \u003C

greater then     ’>’      \u003E

semicolon       ’;’      \u003B


由于在Java字符串中反斜杠也需要转义,所以用2个反斜杠表示:

DN:             cn = Bugs Bunny, o = ACME++, C=US

Canonical form:  cn=bugs bunny,o=acme\+\+,c=us

Java String:     "cn=Bugs Bunny,o=ACME\\+\\+,c=US"


DN中可以使用unicode字符编码,字符串必须规范化并用范式表达后才能进行比较:

alt

        ​属性名称(属性类型)实际转义成对象标志(OIDObject IDentifier),OID采用点分表示法,如2.5.4.3表示属性为cn,由于比较规则中使用的是OID别名,因此在框架实现中不能使用属性名称,而且只有下表列出的属性才可以使用:

commonName           cn       2.5.4.3 ITU X.520

surname                sn       2.5.4.4

countryName            c        2.5.4.6

localityName             l        2.5.4.7

stateOrProvinceName    st        2.5.4.8

organizationName        o       2.5.4.10

organizationalUnitName  ou       2.5.4.11

title                              2.5.4.12

givenName                       2.5.4.42

initials                            2.5.4.43

generationQualifier                 2.5.4.44

dnQualifier                        2.5.4.46

streetAddress        street      RFC 2256

domainComponent    dc        RFC 1274

userid               uid        RFC 1274/2798?

emailAddress                   RFC 2985

serialNumber                   RFC 2985

DN如下:

2.5.4.3=Bugs Bunny,organizationName=ACME,2.5.4.6=US

等价于:

cn=Bugs Bunny,o=ACME,c=US

        属性类型在匹配规则中正式定义,潜在的允许灵活和不灵活2种情况(cases sensitive and case

insensitive)。在上面列表中的都是不灵活匹配,故OSGi DN不依赖灵活匹配的情况。

在X.500标准中支持多值的RDN,但是,他们并不推荐这样用。可以参考文献[13]

Understanding and Deploying LDAP Directory Services。RDN采用加号连接多个值(’+’ \u002B),值之间没有顺序,如下:

cn=Bugs Bunny+dc=x.com+title=Manager,o=ACME,c=US

等价于

dc=x.com+cn=Bugs Bunny+title=Manager, o=ACME, c=US


2.3.7 证书匹配

        证书根据主题DN进行匹配。在匹配之前,DN需要转换成范式,转换的算法在类javax.security.auth.x500.X500Principal中详细描述。

        DN可以使用通配符进行比较,一个通配符(’*’ \u002A)可以代替所有可能的值。由于DN的结构不同,这种匹配比基于字符串格式的通配符要复杂很多。

        一个通配符可以代替RDN中的一个号码或者是一个单独的RDN值。有通配符的DN必须在比较之前进行规范化,这意味着,除了值中的空格,其他空格都要去掉。

通配符的DN格式:

CertificateMatch::= dn-match ( ’;’ dn-match ) *

dn-match       ::= ( ’*’ | rdn-match )

( ’,’ rdn-match ) * | ’-’

rdn-match      ::= name ’=’ value-match

value-match  ::= ’*’ | value-star

value-star    ::= < value, requires escaped ’*’ and ’-’ >


        最简单的例子是只有一个通配符的情况,可以匹配任意DN。一个通配符可以代替DN中的第1个RDN,第1个RDN描述了最没有价值的信息,这样匹配的RDN结果有可能为空。

例如:一个带通配符的DN可以和图2.7的ACME节点的所有子节点匹配:

*, o=ACME, c=US

This wildcard DN matches the following DNs:

这个带通配符的DN与下面这些DN匹配:

cn = Bugs Bunny, o = ACME, c = US

ou = Carots, cn=Daffy Duck, o=ACME, c=US

street = 9C\, Avenue St. Drézéry, o=ACME, c=US

dc=www, dc=acme, dc=com, o=ACME, c=US

o=ACME, c=US

与下面的DN不匹配:

street = 9C\, Avenue St. Drézéry, o=ACME, c=FR

dc=www, dc=acme, dc=com, c=US


        如果在RDN中使用通配符,那么属性值必须用*,这个通配符匹配任意值,但是不能匹配其他的属性值:

cn=*,o=ACME,c=*

可以匹配的DN:

cn=Bugs Bunny,o=ACME,c=US

cn = Daffy Duck , o = ACME , c = US

cn=Road Runner, o=ACME, c=NL

不能匹配的DN:

o=ACME, c=NL

dc=acme.com, cn=Bugs Bunny, o=ACME, c=US


        2种格式的通配符可以同时使用,例如,为了匹配来自ACME公司的所有DN,可以使用:

*, o=ACME, c=*

        匹配DN需要根据上下文环境,证书是证书链的一部分,每个证书都有一个主题DN和发行机构DN,发行机构DN作为主题DN验证证书使用的第一个证书,因此,DN匹配可扩展到对签名者匹配,分号(’;’ \u003B)用于分隔证书链的DN。

下面的例子可用于匹配Tweety公司(美国公司)发行的证书:

* ; ou=S & V, o=Tweety Inc., c=US

        每一个通配符匹配一个空值或者一个证书,但是有时候需要匹配更长的证书链,减号(’-’ \u002D)用来代表匹配零个或者多个证书,而星号只代表匹配一个证书。例如,为了匹配一个证书链中所有由Tweety公司发布的证书,表达式如下:

- ; *, o=Tweety Inc., c=US

        这个例子可以匹配所有由Tweety公司发布的可信证书,证书可信是由于Framework定义实现了。

2.4 权限

        OSGi Framework使用Java2权限来做Bundle安全,而每个Bundle都关联一组权限。在运行期,权限查询通过请求Security Manager,如果Framework使用延迟条件,那么需要install自己的Security Manager,否则Framework可以使用任意的Security Manager。

Bunlde权限的管理通过Conditional Permission Admin、Permission Admin或者其他安全代理。

2.4.1默认权限

        默认权限是指Framework授予Bunlde除具体行为之外的权限,这些权限是正常操作必须的。例如,每个Bundle需要获取Bundle持久化存储区的read,write,detele权限,完整的默认权限如下:

  • 为Bundle持久化存储区授予文件权限(READ,WRITE,DELETE操作)
  • org.osgi.framework.*的读属性权限
  • Bundle自身的Admin权限(RESOURCE,METADATA,CLASS,CONTEXT操作)
  • osgi.eecapability的Capability权限(REQUIRE)

2.4.2权限过滤器

        OSGi支持数字权限关联Bundle,例如:能够授予Bundle Admin权限来管理其他Bundle。

        这个权限名字使用filter表达式描述,当检查权限时,fliter会评估具体Bundle身份的权限属性。例如,一个Bundle能够从具体位置获得Bundle中的所有service注册信息:

ServicePermission("(location=https://www.acme.com/*)", GET )

        这是一个非常强大的模型,由于这个模型允许操作员让一组Bundle密切合作,而且不需要service/package/Bundle的名字空间。另外使用签名或者位置作为目标权限,可以使得权限管理维护量明显降低。个别的Bundle不需要配置:签名者或者位置已经使用有效的分组机制。

filter包含以下的key

id:Bundle Id,例如:(id=256)

location:Bundle的位置,支持filter通配符字符串,允许指定一组Bundle,例如:(location=https://www.acme.com/download/*)

signer:DN链,具体参考2.3.7证书匹配一节。例:(signer=\*,o=ACME,c=NL)

name:Bundle的名称。支持fliter通配符字符串,允许指定具体的一组Bundle,通过一个简单的符号名来映射Bundle,例如:(name=com.acme.*)

权限的name参数也能使用单一的星号通配符(’*’ \u002A),这样表示所有Bundle都匹配。

2.4.2.1多重签名

        一个Bundle可以有多个签名者,这种情况下,签名者可以匹配任意签名者的DN。使用多个签名不仅是属性而且可能有潜在风险,从管理的角度看是有利于使用签名来处理分组,然而,多个签名也能被使用于可信Bundle的恶意管理。

        例如,一个可信Bundle签名为T,后续增加了不可信签名部分U。授予Bundle T和U的权限,通常是必须的。于是,如果权限关联签名U,也就允许Bundle通过U来管理,而且U会意外获得管理可信Bunlde的权限。例如,U能够start和stop这个可信Bundle,于是多个签名也带来了意想不到的问题:Bundle管理要仔细,但是Admin条件权限能够防止这种条件下的潜在风险。


2.5  修改记录

新增默认Capability权限


2.6 参考文献

[1]RFC 2253Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names

http://www.ietf.org/rfc/rfc2253.txt

[2]X.509 Certificates

http://www.ietf.org/rfc/rfc2459.txt

[3]Java 2 Security Architecture

Version 1.2, Sun Microsystems, March 2002

[4]The Java 2 Package Versioning Specification

http://docs.oracle.com/javase/1.4.2/docs/guide/versioning/index.html

[5]Manifest Format

http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#JAR Manifest

[6]Secure Hash Algorithm 1

http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf

[7]RFC 1321 The MD5 Message-Digest Algorithm

http://www.ietf.org/rfc/rfc1321.txt

[8]RFC 1421 Privacy Enhancement for Internet Electronic Mail

http://www.ietf.org/rfc/rfc1421.txt

[9]DSA

http://www.itl.nist.gov/fipspubs/fip186.htm

[10]RSA

http://www.ietf.org/rfc/rfc2313.txt which is superseded by

http://www.ietf.org/rfc/rfc2437.txt

OSGi Core Release 5 Page 21

Security Layer Framework API References

[11]Public Key Cryptography Standard #7

http://www.rsasecurity.com/rsalabs/node.asp?id=2129

[12]Unicode Normalization UAX # 15

http://www.unicode.org/reports/tr15/

[13]Understanding and Deploying LDAP Directory Services

ISBN 1-57870-070-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值