[url=http://blog.csdn.net/kmyhy/article/details/6431609]http://blog.csdn.net/kmyhy/article/details/6431609[/url]
?
本文首先感谢 Apple 开发者论坛的eskimo1,他是我见过的最热心肠的人,对任何人他都不吝于给予无私帮助。
一、
生成证书
keytool -genkey -v
-alias root -keyalg RSA -storetype PKCS12 -keystore dlt.p12 -dname "CN=www.handtimes.com,OU=ipcc,O=云电同方,L=昆明,ST=云南,C=中国"
-storepass ipcc@95598 -keypass ipcc@95598
keytool -genkey -v
-alias p12client -keyalg RSA -storetype PKCS12 -keystore dlt.p12 -dname
"CN=www.handtimes.com,OU=ipcc,O=云电同方,L=昆明,ST=云南,C=中国" -storepass ipcc@95598
-keypass 123456 -validity 1
keytool -list -v
-alias p12client -keystore dlt.p12 -storepass ipcc@95598 -storetype PKCS12
keytool -list -v
-keystore IPCCCA
–
dlt.p12 ipcc@95598 -storetype PKCS12
keytool -export
-alias p12client -keystore dlt.p12 -storetype PKCS12 -storepass ipcc@95598 -rfc
-file p12.cer
keytool -printcert
-v -file /Users/kmyhy/Desktop/client.cer
Keytool.exe
-importkeystore -srckeystore IPCCCA -srcstoretype jks -srcstorepass ipcc@95598 -srcalias
p12client?
-destkeystore dltclient.p12
-deststoretype pkcs12 -deststorepass ipcc@95598 -destkeypass 123456
–
validity 3
重新输入密码
123456,回车,将在用户主目录下生成dltclient.p12文件。
keytool.exe -list
-keystore dltclient.p12 -storepass ipcc@95598 -storetype pkcs12
?
可以看到其中包含了证书和私钥
,并且其认证指纹是和IPCCCA中的一模一样的。
一、
提供证书下载
[/b]
[b]
class
[/b]
GetP12Cert
[b]
extends
[/b]
HttpServlet {
[b]
private
[/b]
[b]
static
[/b]
[b]
final
[/b]
[b]
long
[/b]
[i]
serialVersionUID
[/i]
= 1L;
???
[b]
private
[/b]
[b]
static
[/b]
[b]
final
[/b]
[b]
int
[/b]
[i]
max_days
[/i]
=1;??
???
/**
????
*
[b]
@see
[/b]
HttpServlet#HttpServlet()
????
*/
???
[b]
public
[/b]
GetP12Cert() {
???????
[b]
super
[/b]
();
???????
//
[b]
TODO
[/b]
Auto-generated constructor stub
???
}
/**
?
*
[b]
@see
[/b]
HttpServlet#doGet(HttpServletRequest
request, HttpServletResponse response)
?
*/
[b]
protected
[/b]
[b]
void
[/b]
doGet(HttpServletRequest
request, HttpServletResponse response)
[b]
throws
[/b]
ServletException, IOException {
String filename=
"C://Documents and
Settings//Administrator//dlt.cer"
;
String pass=
"ipcc@95598"
;
Pkcs12Manager man=
[b]
null
[/b]
;
String alias=
"p12client"
;
String keypass=
"123456"
;
[b]
try
[/b]
{
man=
[b]
new
[/b]
Pkcs12Manager(
[b]
new
[/b]
File(filename),pass);
man.updateExpiration(alias,
keypass,
[i]
max_days
[/i]
);
exportCert(man,alias,response);
//
man.saveCert(alias,
"123456");
//man.saveCert(alias,
"123456");
}
[b]
catch
[/b]
(Exception e){
e.printStackTrace();
}
}
//
导出证书
[b]
private
[/b]
[b]
void
[/b]
exportCert(Pkcs12Manager
man,String alias,HttpServletResponse response){
OutputStream out=
[b]
null
[/b]
;
[b]
try
[/b]
{
???
Certificate cert = man.
keyStore
.getCertificate(alias);
???
//
得到证书内容(以编码过的格式)
???
[b]
byte
[/b]
[] buf = cert.getEncoded();
//
写证书文件
???
response.setContentType(
"application/x-download"
);??
???
response.addHeader(
"Content-Disposition"
,
"attachment;filename="
?
???????????
+ man.
file
.getName());??
???
out= response.getOutputStream();
???
out.write(buf);
???
}
[b]
catch
[/b]
(Exception e){e.printStackTrace();}
[b]
finally
[/b]
{
[b]
try
[/b]
{
out.close();
}
[b]
catch
[/b]
(Exception e){
}
}
}
/**
?
*
[b]
@see
[/b]
HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
?
*/
[b]
protected
[/b]
[b]
void
[/b]
doPost(HttpServletRequest request, HttpServletResponse response)
[b]
throws
[/b]
ServletException,
IOException {
doGet(request,response);
}
[/b]
[b]
class
[/b]
Pkcs12Manager {
???
[b]
public
[/b]
File
file
;
???
[b]
public
[/b]
KeyStore
keyStore
;
???
[b]
private
[/b]
[b]
char
[/b]
[]
storePass
;
???
[b]
public
[/b]
Pkcs12Manager(File file, String pass)
[b]
throws
[/b]
IOException, Exception {
???????
[b]
this
[/b]
.
file
= file;
???????
[b]
this
[/b]
.
storePass
=pass.toCharArray();
???????
getKeyStore();
//
加载
KeyStore
文件
???
}
???
//
加载
KeyStore
文件
???
[b]
public
[/b]
[b]
synchronized
[/b]
KeyStore getKeyStore()
[b]
throws
[/b]
IOException, Exception {
???????
[b]
if
[/b]
(
keyStore
==
[b]
null
[/b]
) {
???????????
FileInputStream fin =
[b]
new
[/b]
FileInputStream(
file
);
???????????
KeyStore store = KeyStore.[i]getInstance[/i]
(
"PKCS12"
);
???????????
[b]
try
[/b]
{
???????????????
store.load(fin,
storePass
);???????????????
???????????
}
???????????
[b]
finally
[/b]
{
???????????????
[b]
try
[/b]
{
??????????????????
?
fin.close();
???????????????
}
[b]
catch
[/b]
(IOException e) { }
???????????
}
???????????
keyStore
= store;
???????
}
???????
[b]
return
[/b]
keyStore
;
???
}
???
//
读取
alias
指定的证书内容
[b]
public
[/b]
X509CertInfo
getX509CertInfo(String alias)
[b]
throws
[/b]
Exception {
X509CertImpl cimp=getX509CertImpl(alias);
//
获取
X509CertInfo
对象
[b]
return
[/b]
(X509CertInfo) cimp.get(X509CertImpl.
[i]
NAME
[/i]
+
"."
+ X509CertImpl.
[i]
INFO
[/i]
);
}
???
//
根据
alias
获取
X509CertImpl
对象
[b]
private
[/b]
X509CertImpl
getX509CertImpl(String alias)
[b]
throws
[/b]
Exception{
Certificate c =
keyStore
.getCertificate(alias);
//
读取证书
//
从待签发的证书中提取证书信息
[b]
byte
[/b]
[] enc = c.getEncoded();
//
获取
证书内容(经过编码的字节)
X509CertImpl cimp=
[b]
new
[/b]
X509CertImpl(enc);
//
创建
X509CertImpl
象
[b]
return
[/b]
cimp;
}
//
修改证书过期时间
:
过期时间顺延
n
天
[b]
public
[/b]
[b]
void
[/b]
updateExpiration(String
alias,String keypass,
[b]
int
[/b]
n)
[b]
throws
[/b]
Exception{
System.
[i]
out
[/i]
.println(getExpiration(alias));
X509CertInfo cinfo=getX509CertInfo(alias);
//
获取
X509CertInfo
对象
X509CertImpl cimp=getX509CertImpl(alias);
//
获取
X509CertImpl
对象
String sigAlgrithm=cimp.getSigAlgName();
//
获取签名算法
CertificateValidity
cv=(CertificateValidity)cinfo.get(X509CertInfo.
[i]
VALIDITY
[/i]
);
//
有效期为当前日期后延
n
天
Date d2 =
[b]
new
[/b]
Date(
[b]
new
[/b]
Date().getTime() + n * 24 * 60 * 60 *
1000L);
System.
[i]
out
[/i]
.println(
"new date:"
+d2.toString());
//
创建有效期对象
cv.set(CertificateValidity.
[i]
NOT_AFTER
[/i]
, d2);
cinfo.set(X509CertInfo.
[i]
VALIDITY
[/i]
, cv);
//
设置有效期
saveCert(alias,keypass,cinfo,sigAlgrithm);
System.
[i]
out
[/i]
.println(getExpiration(alias));
}
//?
读取证书过期时间
[b]
public
[/b]
String
getExpiration(String alias)
[b]
throws
[/b]
Exception{
X509CertInfo cinfo=getX509CertInfo(alias);
CertificateValidity
cv=(CertificateValidity)cinfo.get(X509CertInfo.
[i]
VALIDITY
[/i]
);
//
创建有效期对象
Date d=(Date)cv.get(CertificateValidity.
[i]
NOT_AFTER
[/i]
);
[b]
return
[/b]
d.toString();
}
//?
存储证书
[b]
private
[/b]
[b]
void
[/b]
saveCert(String
alias,String keypass,
X509CertInfo
cinfo,String algrithm)
[b]
throws
[/b]
Exception{
//
从密钥库中读取
CA
的私钥
PrivateKey pKey = (PrivateKey)
keyStore
.getKey(alias,
keypass.toCharArray());
X509CertImpl cert =
[b]
new
[/b]
X509CertImpl(cinfo);
//
新建证书
cert.sign(pKey,
algrithm);
//
使用
CA
私钥对其签名
//
获取别名对应条目的证书链
Certificate[]
chain =
[b]
new
[/b]
Certificate[] { cert };
//
向密钥库中添加条目
,
使用已存在别名将覆盖已存在条目
keyStore
.setKeyEntry(alias, pKey,
keypass.toCharArray(), chain);
//
将
keystore
存储至文件
FileOutputStream
fOut =
[b]
new
[/b]
FileOutputStream(
file
);
keyStore
.store(fOut,
storePass
);
fOut.close();
}
//
获取签名算法
[b]
public
[/b]
String
getSigAlgName(String alias)
[b]
throws
[/b]
Exception{
Certificate c =
keyStore
.getCertificate(alias);
//
读取证书
//
获取
证书内容(经过编码的字节)
[b]
byte
[/b]
[] enc = c.getEncoded();
//
创建
X509CertImpl
对象
X509CertImpl cimp2 =
[b]
new
[/b]
X509CertImpl(enc);
String sigAlgrithm=cimp2.getSigAlgName();
[b]
return
[/b]
sigAlgrithm;
}
Servlet
和javabean 部署到服务器中。这样,通过访问
http://localhost/GetP12Cert
就可以获得一个有效的证书dlt.cer。
二、
证书的验证
* path=[[
NSBundle
mainBundle
]
pathForResource
:
@"dlt.cer"
ofType
:
nil
];
参数为任意一个有效的日期(在证书有效期之内)
* myTrust=[[
MyTrustService
alloc
]
initWithFilename
:path
EfficientDate
:
@"2011-05-10 0:0:0"
];
ret=[myTrust
trustValuate
:[[
NSDate
alloc
]
init
]];
(ret) {
case
ValuateResultOK
:
NSLog
(
@"
证书有效
"
);
break
;
case
ValuateResultEXPIRED
:
NSLog
(
@"
证书已过期
"
);
break
;
default
:
NSLog
(
@"
证书校验失败
"
);
break
;
release
];
const
char
*
kTrustNames
[
8
] = {
"Invalid"
,
"Proceed"
,
"Confirm"
,
"Deny"
,
"Unspecified"
,
"RecoverableTrustFailure"
,
"FatalTrustFailure"
,
"OtherError"
enum
ValuateResultINVALID
=
0
,
//
评估结果无效,表明评估出错或未经过评估
ValuateResultFAILED
,
//
证书签名无效
ValuateResultEXPIRED
,
//
证书过期
ValuateResultOK
//
证书有效
MyTrustService :
NSObject {
NSString
*
file
;
NSDate
*
efficientDate
;
id
)initWithFilename:(
NSString
*)filename EfficientDate:(
NSString
*)date;
ValuateResult
)trustValuate:(
NSDate
*)date;
ValuateResult
)valuate:(
SecCertificateRef
)cert Trust:(
SecTrustRef
)trust Date:(
NSDate
*)date;
"MyTrustService.h"
MyTrustService
id
)initWithFilename:(
NSString
*)filename
EfficientDate:(
NSString
*)date{
if
(
self
=[
super
init
]) {
file
=filename;
//
设置有效日期,注意,第
2
个参数是一个有效的证书日期,只要这个日期对证书而言是有效的就行
efficientDate
=[[
NSDate
alloc
]
initWithString
:date];
}
return
self
;
ValuateResult
)trustValuate:(
NSDate
*)date{
ValuateResult
ret;
OSStatus
???????????
err;
???
NSData
*???????????
certData;
???
SecCertificateRef
??
cert;
???
SecPolicyRef
???????
policy;
???
SecTrustRef
????????
trust;
?
???
assert
(
file
!=
nil
);
???
assert
(date !=
nil
);
//
从文件获得
DER
数据
???
certData = [
NSData
dataWithContentsOfFile
:
file
];
???
assert
(certData !=
nil
);
//
从
NSData
获得
Certificate
对象
???
cert =
SecCertificateCreateWithData
(
NULL
, (
CFDataRef
) certData);
???
assert
(cert !=
NULL
);
//
获得
x509 policy
???
policy =
SecPolicyCreateBasicX509
();
???
assert
(policy !=
NULL
);
//
获得
Trust
对象
???
err =
SecTrustCreateWithCertificates
(cert,
policy, &trust);
???
assert
(err ==
noErr
);
//
由于是自签名证书,需要将锚证书设置为要验证的证书自己。注意,这样将使所有除了参数指定的锚证书之外的所有锚证书无效
???
err =
SecTrustSetAnchorCertificates
(trust,
(
CFArrayRef
) [
NSArray
arrayWithObject
:(
id
) cert]);
???
assert
(err ==
noErr
);
//
调用
valuate
方法进行评估
ret=[
self
valuate
:cert
Trust
:trust
Date
:date];
//
评估结束,把
SecTrustSetAnchorCertificates
指定的锚证书失效,于是所有锚证书又可被信任了
??
err=
SecTrustSetAnchorCertificatesOnly
(trust,
NO
);
???
CFRelease
(trust);
???
CFRelease
(policy);
???
CFRelease
(cert);
return
ret;
ValuateResult
)valuate:(
SecCertificateRef
)cert Trust:(
SecTrustRef
)trust Date:(
NSDate
*)date{
ValuateResult
ret;
OSStatus
???????????
err;
???
SecTrustResultType
?
result;
???
err =
SecTrustSetVerifyDate
(trust,
(
CFDateRef
) date);
???
assert
(err ==
noErr
);
CFAbsoluteTime
trustTime;
trustTime =
SecTrustGetVerifyTime
(trust);
???
err =
SecTrustEvaluate
(trust,
&result);
???
assert
(err ==
noErr
);
???
if
(result < (
sizeof
(
kTrustNames
) /
sizeof
(*
kTrustNames
))) {
// if(result < 8)
???????
if
(result==
5
) {
// if result=RecoverableTrustFailure
//
设了个有效的日期,进行再次评估
err=
SecTrustSetVerifyDate
(trust, (
CFDateRef
)
efficientDate
);
assert
(err==
noErr
);
err=
SecTrustEvaluate
(trust, &result);
assert
(err ==
noErr
);
if
(result==
4
) {
// if result=Unspecified,
//
返回证书已过期,这里我们假设把证书尚未生效的情况也算作过期
ret=
ValuateResultEXPIRED
;
}
}
else
if
(result==
4
) {
//
如果第
1
次就通过评估,证书有效
ret=
ValuateResultOK
;
}
else
{
ret=
ValuateResultFAILED
;
//
证书
无效
}
???
}
else
{
???????
NSLog
(
@"result = unknown (%zu)"
, (
size_t
) result);
???
}
return
ret;
void
)dealloc{
[
efficientDate
release
];
[
super
dealloc
];