快速入门

本节介绍如何快速使用pki Java SDK完成常见操作,如创建证书、查询证书、删除证书、下载证书等pki服务,所有操作都是通过IotPkiManageClient与pki服务进行交互。

具体接口参数定义详细请参考API文档

创建IotPkiManageClient

IotPkiManageClient是与pki服务交互的客户端,PKI Java SDK的PKI操作都是通过IotPkiManageClient完成的。用户可以参考创建IotPkiManageClient,完成初始化客户端的操作。

String ACCESS_KEY_ID = <your-access-key-id>;               // 用户的Access Key ID
String SECRET_ACCESS_KEY = <your-secret-access-key>;       // 用户的Secret Access Key
String ENDPOINT = "http://pkiiov.baidubce.com";            // pki服务域名,可根据环境选择具体域名

// 创建配置
BceClientConfiguration config = new BceClientConfiguration()
                .withCredentials(new DefaultBceCredentials(ACCESS_KEY_ID, SECRET_ACCESS_KEY))
                .withEndpoint(ENDPOINT);

// 初始化一个IotPkiManageClient
IotPkiManageClient iotPkiManageClient = new IotPkiManageClient(config);

在上面代码中,变量ACCESS_KEY_ID与SECRET_ACCESS_KEY是由系统分配给用户的,均为字符串,用于标识用户,为访问pki服务做签名验证。其中ACCESS_KEY_ID对应控制台中的“Access Key ID”,SECRET_ACCESS_KEY对应控制台中的“Access Key Secret”,获取方式请参考获取AK/SK。

参数说明

BceClientConfiguration中有更多的配置项,可配置如下参数:

参数 说明
connectionTimeoutInMillis 建立连接的超时时间(单位:毫秒)
localAddress 本地地址
maxConnections 允许打开的最大HTTP连接数
protocol 连接协议类型
proxyDomain 访问NTLM验证的代理服务器的Windows域名
proxyHost 代理服务器主机地址
proxyPassword 代理服务器验证的密码
proxyPort 代理服务器端口
proxyPreemptiveAuthenticationEnabled 是否设置用户代理认证
proxyUsername 代理服务器验证的用户名
proxyWorkstation NTLM代理服务器的Windows工作站名称
retryPolicy 连接重试策略
socketBufferSizeInBytes Socket缓冲区大小
socketTimeoutInMillis 通过打开的连接传输数据的超时时间(单位:毫秒)
userAgent 用户代理,指HTTP的User-Agent头

创建根证书

String country = "CN";                                    //国家/地区
String commonName = "pki";                                //常用名称
String organization = "baidu";                            //组织
String unit = "iot";                                      //组织单位
String emailAddress = "user@baidu.com";                   //电子邮件地址

int duration = 3650;                                      //根证书有效期,以天为单位
String clientToken = "abcdefghijklmnopqrs";               //随机字符串,用来保证幂等性

//创建根证书基本信息
CreateRootCACertRequest.CertRequestInfo certRequestInfo = new CertRequestInfo()
        .withOrganization(organization)
        .withCommonName(commonName)
        .withCountry(country)
        .withUnit(unit)
        .withEmailAddress(emailAddress);


//生成创建请求
CreateRootCACertRequest request = new CreateRootCACertRequest()
        .withCertRequestInfo(certRequestInfo)
        .withDuration(duration);


//创建根证书,返回根证书的id
String rootCertId = iotPkiManageClient.createRootCACert(request, clientToken).getCertId();

说明:

  • 根证书的commonName是全局唯一的,因此创建多个根证书时需要保证commonName不相同。
  • 创建成功会返回根证书的id,pki服务通过用户id和证书id来唯一确定一个证书。
  • clientToken用来保证创建的幂等性,幂等性的意思是无论同一个请求被重复发送多次,其结果都和发送一次一样。这个字段是为了避免由于网络等问题导致客户端没收到响应连接就中断,然后客户端重试导致重复创建的问题。

创建证书组

String rootCertId = "abcdefghijklmnopqrs";                //根证书id,在创建根证书时由pki服务返回
String groupName = "group";                               //证书组名称

String clientToken = "abcdefghijklmnopqrs";               //随机字符串,用来保证幂等性

//生成创建请求
CreateCertGroupRequest request = new CreateCertGroupRequest()
        .withRootCertId(rootCertId)
        .withGroupName(groupName);

//生成证书组,返回证书组id
String groupId = iotPkiManageClient.createCertGroup(request, clientToken).getGroupId();

创建子证书

String groupId = "abcdefghijklmnopqrs";                   //证书组id,在创建证书组时由pki服务返回
String deviceId = "device0";                              //设备id
int duration = 3650;                                      //子证书有效期,不能超过签发该证书的根证书的有效期

String clientToken = "abcdefghijklmnopqrs";               //随机字符串,用来保证幂等性

//子证书csr文件
String csr = "-----BEGIN CERTIFICATE REQUEST-----
MIICqDCCAZACAQAwYzELMAkGA1UEBhMCQ04xDjAMBgNVBAoMBWJhaWR1MQwwCgYD
VQQLDANhaWQxFzAVBgNVBAMMDmNsaWVudDNhZmFmODE5MR0wGwYJKoZIhvcNAQkB
Fg50ZXN0QGJhaWR1LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALjfDeQ2qwpkJnJEieE2HyRiEX+rkAmYg6ahJ4CRjcu4gAfYMJe6W/dx2s3aV1oK
PnbaIxMKqjJ3pka6EtieaUyT7hlsIvZVrc80caUS6Y93olDQr122mnjllX4moKOw
PkLa6sUoK4HB9dPYfxyoyzoK03daYXyjXptuOhIArAltRoSzuMGodB4W3Wn6aKcR
da3OmTZ+BquPtYE8ASQ7kzcTpd2tBQxL/NxtCHr+eaCq7DxU/SAKJwjL1vqtelJp
l2SUiITK93xHLUAYy7wUt5lbKskNq3iBjCLNsBdf/CvgHgRliXmrxtyCdA09nHO1
wlQ+Fo7Ptwve5k2gYsCVsc8CAwEAAaAAMA0GCSqGSIb3DQEBDQUAA4IBAQCGYfOV
APUTOCvyusTBKZ2YMgv+9m+DRWmqbFImDzTmH9wJM+DhxW62ukZWNqKZQmpiapSa
AkEXrkvUk5m+t/p4LsOC2Q0u6r4iC+MwyWmYI+/muUempnMfA2Gb2pZzujtqMIbu
Rldl8CS6VxORHVUaW1pbCadUJoT3jOdbm67UdLX2bcWTpPtHhagUGzxiRFRsD8vr
oYstIj+UZnF/KOGSM3EaBALtNeYvYmh9YIeEb7Akfd5pM6lYGNuvRMuc70Y1tKLm
svqaDdsQ3TzQdDOKZDijPBrrJIdUScjvjrzkPRZBxy4WQseoSmaCyvtiXyK1HfKp
D3G6ok2bnpJlioaE
-----END CERTIFICATE REQUEST-----";

CreateSubCertRequest request = new CreateSubCertRequest()
        .withGroupId(groupId)
        .withDeviceId(deviceId)
        .withDuration(duration)
        .withCsr(csr);

//创建客户端子证书
CreateSubCertResponse response = iotPkiManageClient.createClientCert(request, clientToken);

//获取所创建的客户端子证书id
String certId = response.getCertId(); 
//获取所创建的客户端子证书下载链接
String downloadUrl = response.getDownloadUrl();
  • csr文件是证书申请者在申请数字证书时由CSP(加密服务提供者)在生成私钥的同时生成的,详见api参考文档。
  • 用户可以通过downloadUrl直接下载证书内容。

上述代码是创建客户端子证书,服务端子证书的创建只需在创建请求中加入address字段:

List<String> address = Arrays.asList("addr1", "addr2");

CreateSubCertRequest request = new CreateSubCertRequest()
        .withGroupId(groupId)
        .withDeviceId(deviceId)
        .withDuration(duration)
        .withCsr(csr)
        .withAddress(address);

//创建服务端子证书
CreateSubCertResponse response = iotPkiManageClient.createServerCert(request, clientToken);

批量创建客户端子证书

//子证书csr文件
String csr = "-----BEGIN CERTIFICATE REQUEST-----
MIICqDCCAZACAQAwYzELMAkGA1UEBhMCQ04xDjAMBgNVBAoMBWJhaWR1MQwwCgYD
VQQLDANhaWQxFzAVBgNVBAMMDmNsaWVudDNhZmFmODE5MR0wGwYJKoZIhvcNAQkB
Fg50ZXN0QGJhaWR1LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALjfDeQ2qwpkJnJEieE2HyRiEX+rkAmYg6ahJ4CRjcu4gAfYMJe6W/dx2s3aV1oK
PnbaIxMKqjJ3pka6EtieaUyT7hlsIvZVrc80caUS6Y93olDQr122mnjllX4moKOw
PkLa6sUoK4HB9dPYfxyoyzoK03daYXyjXptuOhIArAltRoSzuMGodB4W3Wn6aKcR
da3OmTZ+BquPtYE8ASQ7kzcTpd2tBQxL/NxtCHr+eaCq7DxU/SAKJwjL1vqtelJp
l2SUiITK93xHLUAYy7wUt5lbKskNq3iBjCLNsBdf/CvgHgRliXmrxtyCdA09nHO1
wlQ+Fo7Ptwve5k2gYsCVsc8CAwEAAaAAMA0GCSqGSIb3DQEBDQUAA4IBAQCGYfOV
APUTOCvyusTBKZ2YMgv+9m+DRWmqbFImDzTmH9wJM+DhxW62ukZWNqKZQmpiapSa
AkEXrkvUk5m+t/p4LsOC2Q0u6r4iC+MwyWmYI+/muUempnMfA2Gb2pZzujtqMIbu
Rldl8CS6VxORHVUaW1pbCadUJoT3jOdbm67UdLX2bcWTpPtHhagUGzxiRFRsD8vr
oYstIj+UZnF/KOGSM3EaBALtNeYvYmh9YIeEb7Akfd5pM6lYGNuvRMuc70Y1tKLm
svqaDdsQ3TzQdDOKZDijPBrrJIdUScjvjrzkPRZBxy4WQseoSmaCyvtiXyK1HfKp
D3G6ok2bnpJlioaE
-----END CERTIFICATE REQUEST-----";

Map<String, String> deviceIdAndCsr = new HashMap<String, String>(); //deviceId到csr的映射,deviceId要和csr一一对应
String deviceId = "deviceId";                             //设备id
String groupId = "abcdefghijklmnopqrs";                   //证书组id,在创建证书组时由pki服务返回
deviceIdAndCsr.put(deviceId, csr);

int duration = 3650;                                      //子证书有效期,不能超过签发该证书的根证书的有效期
String clientToken = "abcdefghijklmnopqrs";               //随机字符串,用来保证幂等性

//生成批量创建请求
BatchCreateClientCertRequest request = BatchCreateClientCertRequest.create(groupId, duration, deviceIdAndCsr);

//批量创建客户端子证书并获取创建任务的jobId
String jobId = iotPkiManageClient.batchCreateClientCert(request, clientToken).getJobId();

批量创建客户端子证书是一个异步任务(也就是说,pki服务返回jobId时,批量创建任务可能还在进行中),
需要用户在后续查询批量任务状态,并根据状态进行进一步操作(等待、重试或者下载),详见API参考文档

查询和下载根证书

根证书在发出创建请求后,只会返回一个certId,因此,要下载根证书,首先要获取其下载链接:

String rootCertId = "abcdefghijklmnopqrs";                 //根证书id,创建根证书时由pki服务返回

//查询根证书
GetRootCACertResponse response = iotPkiManageClient.getRootCACert(rootCertId);

//获取根证书crl列表下载链接
String crl = response.getCrl();
//获取根证书下载链接
String downloadUrl = response.getDownloadUrl();

crl列表记录了该根证书下被删除(废弃)的、且未过期的子证书。详见API参考文档
在拿到downloadUrl之后,用户就可以通过downloadUrl直接下载证书内容。

查询证书组

String groupId = "abcdefghijklmnopqrs";                  //证书组id,创建证书组时由pki服务返回

//查询证书组
GetCertGroupResponse response = iotPkiManageClient.getCertGroup(groupId);

//获取证书对应的根证书
String rootCertId = response.getRootCertId();

//获取证书组下的服务端子证书id列表
List<String> serverCerts = response.getServerCerts();

//获取证书组下的客户端子证书id列表
List<String> clientCerts = response.getClientCerts();

查询和下载子证书

String certId = "abcdefghijklmnopqrs";                     //子证书id,创建子证书时由pki服务返回

//查询服务端子证书
GetCertResponse response = iotPkiManageClient.getServerCert(certId);

//获取签发该子证书的根证书
String rootCertId = response.getRootCertId();
//获取子证书所在证书组
String groupId = response.getGroupId();
//获取子证书下载链接
String downloadUrl = response.getDownloadUrl();

在拿到downloadUrl之后,用户就可以通过downloadUrl直接下载证书内容。

上述代码是获取服务端子证书,获取客户端子证书只需要调用getClientCert即可:

String certId = "abcdefghijklmnopqrs";                     //子证书id,创建子证书时由pki服务返回

//查询客户端子证书
GetSubCertResponse response = iotPkiManageClient.getClientCert(certId);

查询子证书列表

String rootCertId = "abcdefghijklmnopqrs";                 //根证书id,创建根证书时由pki服务返回
String groupId = "abcdefghijklmnopqrs";                    //证书组id,在创建证书组时由pki服务返回

//根据rootCertId和groupId查询客户端子证书列表
QueryClientCertResponse response = iotPkiManageClient.queryClientCerts(rootCertId, groupId);

//获取客户端子证书id列表
List<String> clientCerts = response.getClientCerts();

这个接口可以根据rootCertId和groupId查询其下的客户端子证书,根据rootCertId和groupId可以分为一下几种情况:

  1. groupId不为空,则根据groupId查询对应证书组下的子证书。这种情况下,pki服务不对rootCertId做任何检查,也不会使用rootCertId。
  2. groupId为空,rootCertId不为空,则根据rootCertId查询对应根证书下的子证书。
  3. groupId和rootCertId都为空,查询失败,pki服务返回错误。

上述代码是查询客户端子证书列表,查询服务端子证书列表只需要调用queryServerCerts即可:

String rootCertId = "abcdefghijklmnopqrs";                 //根证书id,创建根证书时由pki服务返回
String groupId = "abcdefghijklmnopqrs";                    //证书组id,在创建证书组时由pki服务返回

//根据rootCertId和groupId查询服务端子证书列表
QueryServerCertResponse response = iotPkiManageClient.queryServerCerts(rootCertId, groupId);

//获取服务端子证书id列表
List<String> serverCerts = response.getServerCerts();

查询批量创建任务

String jobId = "abcdefghijklmnopqrs";                     //批量创建任务id,创建批量创建任务时由pki服务返回

//查询批量创建任务
GetBatchCreateStatusResponse response = iotPkiManageClient.getBatchCreateStatus(jobId);

//获取批量创建任务状态
JobStatus jobStatus = response.getJobStatus();

查询批量创建任务时,如果状态为Succeed或者PartialSucceed,会同时返回下载连接,用户可直接根据链接下载证书,也可调用下文的下载接口进行下载。详见API参考文档

下载批量创建任务证书

String jobId = "abcdefghijklmnopqrs";                     //批量创建任务id,创建批量创建任务时由pki服务返回

//下载批量创建任务证书
Map<String, String> deviceIdCertMap = iotPkiManageClient.downloadBatchCreateCerts(jobId);

当查询到的批量创建任务为Succeed或者PartialSucceed,可使用本接口进行下载;否则,该接口返回null。
本接口返回的是deviceId到cert的一个映射,用户可根据创建批量创建任务时的deviceId拿到对应的证书文件。

变更子证书

String clientCertId = "abcdefghijklmnopqrs";              //客户端子证书id,创建子证书时由pki服务返回

String clientToken = "abcdefghijklmnopqrs";               //随机字符串,用来保证幂等性

//生成变更子证书请求
RenewSubCertRequest request = new RenewSubCertRequest()
        .withCsr(csr)
        .withDuration(365)
        .withNewDeviceId("new deviceId");

//变更子证书
RenewSubCertResponse response = iotPkiManageClient.renewClientCert(request, clientCertId, clientToken);

//获取新证书的下载地址
String downloadUrl = response.getDownloadUrl();

上述代码是变更客户端子证书,变更服务端子证书只需调用renewServerCert即可:

String serverCertId = "abcdefghijklmnopqrs"              //服务端子证书id,创建子证书时由pki服务返回

String clientToken = "abcdefghijklmnopqrs";               //随机字符串,用来保证幂等性

//生成变更子证书请求
RenewSubCertRequest request = new RenewSubCertRequest()
        .withCsr(csr)
        .withDuration(3650)
        .withNewAddress(Arrays.asList("newAddress"))
        .withNewDeviceId("new deviceId");

//变更子证书并获得新证书的下载地址
String downloadUrl = client.renewServerCert(request, serverCertId, generateClientToken()).getDownloadUrl();

删除证书(或证书组)

删除的接口是一致的,根据证书id或者证书组id删除对应的证书或者证书组。

注意: 删除根证书或者证书组都需要保证该根证书或者证书组下没有子证书,否则删除失败。

String clientCertId = "abcdefghijklmnopqrs";                     //客户端子证书id,创建子证书时由pki服务返回
//删除客户端子证书
iotPkiManageClient.deleteClientCert(clientCertId);

String serverCertId = "abcdefghijklmnopqrs";                     //服务端子证书id,创建子证书时由pki服务返回
//删除服务端子证书
iotPkiManageClient.deleteServerCert(serverCertId);

String groupId = "abcdefghijklmnopqrs";                          //证书组id,创建证书组时由pki服务返回
//删除证书组
iotPkiManageClient.deleteCertGroup(groupId);

String rootCertId = "abcdefghijklmnopqrs";                       //根证书id,创建根证书时由pki服务返回
//删除根证书
iotPkiManageClient.deleteRootCACert(rootCertId);

Crl下载

crl的下载可以直接通过查询根证书时返回的下载链接进行下载。这里提供了另一种下载方式:

//根证书DN(issuerDN),可以在证书文件中找到
String issuerDN = "C=cn, O=bd, OU=iot, CN=CN, EMAILADDRESS=www@baidu";

//下载crl
DownloadCrlResponse response = iotPkiManageClient.downloadCrl(issuerDN);

//获取crl内容
String crl = response.getCrlContent();
这个接口返回的是pem格式的crl,用户需要自行解析。

OCSP查询

在线证书状态协议(Online Certificate Status Protocol)是一个用于获取X.509数字证书撤销状态的网际协议,可以在线实时获取证书状态。具体协议可查看标准ocsp协议。

在生成标准ocsp请求后,可以通过如下方式进行ocsp查询:

//标准ocsp请求,这里只列出了请求的一部分
byte[] ocspRequest = new byte[] { 48, 101, 48, 99, 48, 69, 48, 67, 48, 65, 48, 9, 6, 5}

//ocsp查询,并获取ocsp查询结果(ocspResponse)
byte[] ocspResponse = iotPkiManageClient.getOcspResponse(ocspRequest).getOcspResponse();

这个接口返回的是标准的ocsp响应,用户需要自行解析该响应。

证书状态在线查询

pki服务除了支持以上两种标准的证书状态查询协议,还提供了自定义的证书状态查询接口:

//根证书DN(issuerDN),可以在证书文件中找到
String issuerDN = "C=cn, O=bd, OU=iot, CN=CN, EMAILADDRESS=www@baidu";

//子证书序列号(serial number),可以在证书文件中找到,注意要转换为16进制
String certSN = "123456789abcdef";

//生成在线查询请求
GetCertStatusRequest request = new GetCertStatusRequest()
        .withCertificateSN(certSN)
        .withIssuerDN(issuerDN);

//证书状态在线查询
GetCertStatusResponse response = iotPkiManageClient.getCertStatus(request);

//获取证书状态
CertStatus certStatus = response.getStatus();
certStatus目前有5种状态,详见api参考文档。