IBM i 平台下相关 SSL API 介绍

安全套接字层(SSL)作为一项提供服务器和客户端之间数据加密和鉴权的技术,最初是由网景公司(Netscape)开发并首先在其浏览器产品上使用。随着互联网的普及与发展,现在它已被广泛的应用到各种网络应用当中,如 HTTP、FTP、Telnet 和电子邮件。 IBM i 除了支持 OpenSSL 以外,还支持另外两种 API 库 — GSK(Global Secure ToolKit)和 SSL_ APIs。本文介绍了 GSK 和 _SSL 两种开发库的 API。

盛 彬, 软件工程师, IBM

盛彬是 IBM CSTL 的 IBM i TCP/IP Apps 项目组的一名软件工程师。他所感兴趣和专长的领域包括 TC/IP 协议栈,SMTP, POP3 等。



2012 年 5 月 24 日

关于 SSL

安全套接字层 (SSL) 作为一项提供服务器和客户端之间数据加密和鉴权的技术,最初是由网景公司((Netscape))开发并首先在其浏览器产品上使用(目前版本为 3.0)。随着互联网的普及与发展,现在它已被广泛的应用到各种网络应用当中,如 HTTP、FTP、Telnet 和电子邮件。基于 SSL3.0,IETF(www.ietf.org)在 RFC2246 中对 SSL 作了标准化,并将其称为 TLS(Transport Layer Security),从技术上讲,TLS1.0 与 SSL3.0 的差别非常微小,可以认为是等价的(为了陈述方便下文中我们统一称其为 SSL)。

SSL 其实是在 TCP 之上建立了一个加密通道,通过这一层的数据经过了加密,因此达到保密的效果。SSL 协议分为两部分:Handshake Protocol 和 Record Protocol,。其中 Handshake Protocol 用来协商密钥,协议的大部分内容就是通信双方如何利用它来安全的协商出一份密钥。Record Protocol 则定义了传输的格式。一个基本的 SSL 会话存在“握手”、“下发证书”、“密钥交换和算法协商”和“数据传输”四个阶段(如图 1)。其中“下发证书”和“密钥交换和算法协商”所涉及的 API 比较多,用法也稍复杂。

图 1. SSL 会话基本步骤
图 1. SSL 会话基本步骤

当前 SSL 被很多操作系统和开发库所支持,其中著名的开源项目 OpenSSL 被移植到了很多平台。IBM i 作为一款优秀的商业操作系统当然也对 SSL 提供了良好的支持。除了支持 OpenSSL(PASE 环境下)外,它还另外支持两种原生的 API 库—— GSK(Global Secure ToolKit,从 V4R5 开始被 IBM i 在 ILE 环境下支持)和 _SSL APIs(在 ILE 环境下支持)。下面我们就来详细介绍 IBM i 环境下 GSK 和 _SSL APIs。


Global Secure ToolKit (GSK)

GSK API 支持大部分的 IBM 的操作系统。如果要设计在 IBM 拥有的操作系统之间移植性比较好的程序,GSK 是一个比较好的选择。因为 GSK 已经被 IBM i、z/OS 和 AIX 所支持,移植到另外一种平台的话,只需更改少量宏定义,譬如 GSK_OS400_APPLICATION_ID,程序就可被编译运行。

GSK 的用法

下面我们就以最通用的步骤,来看一下 GSK 最常用的(包括必须用到的)API 的用法。

  1. 使用 QsyRegisterAppForCertUse()(非 GSK API)在系统中注册当前应用程序 ID,这样在 DCM(Digital Certificate Manager)系统中就可以找到此 ID 和配置对用的证书(如何配置请参考 IBM i Inforcenter 上 DCM 相关章节)。
  2. 调用 gsk_environment_open() 申请创建一个 GSK 的环境句柄。请注意,对于一个工作任务,只允许有 64 个 GSK 环境句柄,如超过 64 个的话,gsk_environment_open() 就返回存储空间分配错误—— GSK_INSUFFICIENT_STORAGE。
  3. 将 GSK_OS400_APPLICATION_ID 作为 gsk_attribute_set_buffer() 的第 2 个参数,调用 gsk_attribute_set_buffer() 为 SSL 环境句柄设定应用程序 ID。总的来说,GSK 环境句柄通过 gsk_attribute_set_buffer() 有下列属性可以设置(如表 1)。
表 1. SSL 环境句柄属性
属性说明
GSK_KEYRING_FILE 证书库文件的名字
GSK_KEYRING_PW 证书库文件的密码
GSK_KEYRING_LABEL 证书库在 DCM 中的标签 (Label)
GSK_OS400_APPLICATION_ID 应用程序 ID
GSK_V2_CIPHER_SPECS SSLv2 的加密和鉴权算法列表
GSK_V3_CIPHER_SPECS SSLv3 的加密和鉴权算法列表
  1. 调用 gsk_attribute_set_enum() 设定会话角色为服务端或客户端。如,
    • 设置为服务端,gsk_attribute_set_enum(my_gsk_handle, GSK_SESSION_TYPE, GSK_SERVER_SESSION)。
    • 设置为客户端,gsk_attribute_set_enum(my_gsk_handle, GSK_SESSION_TYPE, GSK_CLIENT_SESSION)

    也可以通过它设置本 SSL 环境内所支持的 SSL 版本。如,

    • 支持 SSL version 2,gsk_attribute_set_enum(my_gsk_handle, GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON);
    • 支持 SSL version 3, gsk_attribute_set_enum(my_gsk_handle, GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON))
    • 不支持 TLS version 1, gsk_attribute_set_enum(my_gsk_handle, GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_OFF));

    而获取和修改当前系统所支持的 SSL 版本,可通过 DSPSYSVAL SYSVAL(QSSLPCL) 和 CHGSYSVAL SYSVAL(QSSLPCL) 这两个命令。

  2. 调用 gsk_environment_init() 初始化指定的 GSK 环境句柄。
  3. 调用 gsk_attribute_get_cert_info() 获取证书信息,通过返回值来检验证书是否已经在本 GSK 环境内被成功加载和启用。
  4. 调用 gsk_secure_soc_open(),在指定的 GSK 环境内为创建一个 SSL 会话句柄。并使用 gsk_attribute_set_numeric_value 关联相关接受的 socket。
  5. 调用 gsk_secure_soc_init() 初始化 SSL 会话句柄。
  6. 接下来可以调用 gsk_secure_soc_read() 和 gsk_secure_soc_write() 进行接收和发送数据了。
  7. 如若需要对 SSL 会话进行一些修改,譬如重置 SSL 会话密码和重置会话,可以使用 gsk_secure_soc_misc() 这个 API。
  8. 关闭 SSL 会话请使用 gsk_secure_soc_close()。
  9. 对于其他新的 SSL 连接,重复 6 - 10 进行处理。
  10. 最后当不在需要一个 SSL 环境句柄时,需要调用 gsk_environment_close() 来关闭 SSL 环境句柄释放资源。

_SSL APIs

对于 IBM i 来说,_SSL APIs 比 GSK 要出现的早一些(V4R5 开始支持 GSK)。它是 IBM i 特有的 SSL 开发库,由于缺乏可移植性等原因现已经逐渐被 GSK 所取代。所以我们强烈建议在开发新的 IBM i SSL 程序时使用 GSK。不过在很多老程序中还存在 _SSL APIs,为了阅读、移植和升级这些程序,我们还是有必要熟悉 _SSL APIs 的用法。

_SSL API 的用法

_SSL APIs 的相关 API 要少一些,使用也比较简单,也不一定需要和 DCM 配合使用。和介绍 GSK 一样,我们也通过最通用的步骤介绍一下 _SSL APIs 最常用的(包括必须用到的)API 的用法

  1. 使用 QlgSSL_Init,SSL_Init 或者 SSL_Init_Application 初始化当前工作任务 SSL 的环境。这三个 API 都只有一个参数,分别为 QlgSSLInit* init (如清单 1)、SSLInit* init(如清单 2)和 SSLInitApp * init_app(如清单 3)。
    清单 1. QlgSSLInit 的数据结构
     struct QlgSSLInit{ 
       Qlg_Path_Name*        keyringFileName; 
       char*                   keyringPassword; 
       unsigned short int*  cipherSuiteList; 
       unsigned int          cipherSuiteListLen; 
     };
    清单 2. SSLInit 的数据结构
     struct SSLInit{ 
       char*                   keyringFileName; 
       char*                   keyringPassword; 
       unsigned short int*  cipherSuiteList; 
       unsigned int           cipherSuiteListLen; 
     };

    前两个 API 参数的数据结构的区别主要是在结构的第一个结构成员变量上。QlgSSLInit 对应的是 Qlg_Path_Name,SSLInit 对应的是 char*,他们均指定了密钥环文件所在路径,只不过前者支持多语言路径(因为除了包含 IFS 路径外还可以指定 CCSID 等信息),而后者只是纯粹的 IFS 路径的字符串(使用本 Job 的 CCSID)。而后三个结构成员变量则相同,需要指定本地私钥和期望的加密和鉴权算法类型列表。对于加密和鉴权算法类型,<qsossl.h> 中列举并了定义所有的加密和鉴权算法和它对应的常量代表值,我们可以根据需要从中选取。在 IBM i 系统中支持以下加密和鉴权算法(如表 2),

表 2. IBM i 下的加密和鉴权算法
C 常量HEX系统值备注
TLS_RSA_WITH_NULL_MD5 0x0001 *RSA_NULL_MD5
TLS_RSA_WITH_NULL_SHA 0x0002 *RSA_NULL_SHA
TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003 *RSA_EXPORT_RC4_40_MD5
TLS_RSA_WITH_RC4_128_MD5 0x0004 *RSA_RC4_128_MD5
TLS_RSA_WITH_RC4_128_SHA 0x0005 *RSA_RC4_128_SHA
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD50x0006 *RSA_EXPORT_RC2_CBC_40_MD5
TLS_RSA_WITH_DES_CBC_SHA 0x0009 *RSA_DES_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A *RSA_3DES_EDE_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA 0x002F *RSA_AES_128_CBC_SHA TLSv1 有效
TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 *RSA_AES_256_CBC_SHA TLSv1 有效
TLS_RSA_WITH_RC2_CBC_128_MD5 0xFF01*RSA_RC2_CBC_128_MD5 SSLv2 有效
TLS_RSA_WITH_DES_CBC_MD5 0xFF02 *RSA_DES_CBC_MD5 SSLv2 有效
TLS_RSA_WITH_3DES_EDE_CBC_MD5 0xFF03 *RSA_3DES_EDE_CBC_MD5 SSLv2 有效

其中 TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_RC4_128_MD5, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA 为默认系统安装的加密和鉴权算法。

通过 DSPSYSVAL SYSVAL(QSSLCSL) 和 DSPSYSVAL SYSVAL(QSSLCSL) 可以查看和修改当前系统支持的加密和鉴权算法列表。

对于 SSL_Init_Application() 这个 API,它的参数数据结构要复杂一些(如清单 3)。

清单 3. SSLInitApp 的数据结构
 struct SSLInitApp{               
   char*                 applicationID;       
   unsigned int           applicationIDLen;    
   char*                   localCertificate;    
   unsigned int           localCertificateLen; 
   unsigned short int*   cipherSuiteList; 
   unsigned int           cipherSuiteListLen;    
   unsigned int           sessionType; 
   unsigned int           reserved1;           
   unsigned int           protocol;              
   unsigned int           timeout;               
   char                     reserved[12]; 
 };

前两个结构成员变量指定了当前工作任务的应用程序 ID。和 GSK 中一样,此 ID 需使用 QsyRegisterAppForCertUse 在系统中注册并在 DCM 中配置它。第 3 个第 4 个结构成员变量传递了一个分配好的内存空间和长度,供后续 API 返回本地证书内容。不过一般不需要返回本地证书内容,这样在程序只需把这两个值设置成 NULL 和 0。第 5 和第 6 个结构成员变量则和前两个 API 参数数据结构的后两个参数含义相同。第 7 个结构成员变量则会返回会话类型,它的值来源于 使用 QsyRegisterAppForCertUse() 所注册的应用程序类型(Application Control Keys 的第 8 个 Key 的值)。第 8 个结构成员变量为预留成员变量,必须设为 0。第 9 个结构成员变量用作设定 SSL 协议的版本。第 10 个则设定了用于 SSL v3 和 TLS v1 的会话参数缓存刷新的 SSL 简短握手 (abbreviated handshake) 的时间间隔(单位为秒),它的最小值为 1,最大值是 86,400(24 小时)。如想禁用 SSL 而当此值设置为 0XFFFFFFF 时,则表示禁用 SSL 会话参数缓存。最后一个结构成员变量是保留变量,对于这 char 型数组使用时须全置 0。

  1. 调用 SSL_Create() 绑定已经建立好的 socket,并创建 SSL 会话的数据结构的句柄(如清单 4)。然后设定此句柄结构的相关成员变量。
    清单 4. SSLHandle 的数据结构
     struct SSLHandle{                         
       int              fd;                       
       int              createFlags;              
       unsigned         protocol;                 
       unsigned         timeout;                  
       unsigned         char cipherKind[3];       
       unsigned         short int cipherSuite;    
       unsigned         short int* cipherSuiteList; 
       unsigned int    cipherSuiteListLen;                         
       unsigned         char* peerCert;           
       unsigned         peerCertLen;              
       int              peerCertValidateRc;            
       int             (*exitPgm)(struct SSLHandle* sslh); 
     };

    通常我们需要设定的结构成员变量是第 4 个—— timeout。这个值表示等待握手成功的最大等待时间,设为 0 表示永远等待。

  2. 将 SSL_Create() 返回并经过我们修改的 SSL_Handle 作为参数 1,并指定本地握手角色作为参数 2,调用 SSL_Handshak() 开始和对方握手。
  3. 调用 SSL_Read() 和 SSL_Write() 进行发送和接受数据。
  4. 如会话结束则调用 SSL_Destroy() 来结束 SSL 会话。
  5. 对于其它新的 SSL 连接,则重复步骤 2 - 5。

结束语

在当前网络环境下,在程序中使用 SSL 会大大提升数据传输的安全系数。当然在实际开发过程中,会涉及到更多的细节和更多的 API,而上文只是介绍了常用 API 的部分用法。对于每个 API 的具体细节,请参考 IBM i 信息中心 中的 SSL 相关部分,那里给出了详细的描述。同时如需要对 SSL 协议本身做深入的了解,请访问 IETF 网站(www.ietf.org),参考 SSL 和 TLS 相关的 RFC 文档。

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=IBM i, SOA and web services
ArticleID=818092
ArticleTitle=IBM i 平台下相关 SSL API 介绍
publish-date=05242012