samuel
发贴: 50
积分: 10
|
于 2003-08-22 11:30
KeyManager
javax.net.ssl.X509KeyManager有六个方法: · getClientAliases()返回一组客户端别名。(这里的一个别名就是带有一个RSA私钥和证书的一个身份。) · getServerAliases()返回一组服务器别名。 · chooseClientAlias()从一组别名中选择一个客户端别名。 · chooseServerAlias()从一组别名中选择一个服务器别名。 · getCertificateChain()为一个证书返回有序的证书链。 · getPrivateKey()为一个别名返回私钥。
Microsoft将私钥和它们相关的证书存储在文件系统中。我的私钥和证书存储在目录C:\Documents和Settings\Administrator\Application Data\Microsoft中。你不需要知道钥匙存储在哪里,因为Microsoft提供了一个API用来访问钥匙和证书库。
KeyManager的getClientAliases()和getServerAliases()方法执行Microsoft本地的函数CertEnumCertificateslnStore(),查看Microsoft的“My”证书库中的所有证书。“My”证书库中的证书应该有一个与它们相关连的私钥。每个证书/私钥组合都有一个特殊的标识符,称为CONTAINER;这就相当于Java中的“别名”(见列表5)。
CertEnumCertificatesInStore()方法查看Microsoft中“My”证书库中所有的证书;每个证书都有一个相关的私钥。每个证书/私钥组合都有一个标识符,称为CONTAINER,这就相当于Java中的别名。 JobjectArray MSgetAliases (jstring jcertStore) { // open Microsoft certificate store hSystemStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, certStore);
// read all the certificates while(pCertContext= CertEnumCertificatesInStore( hSystemStore, pCertContext)) {
// get the cert key container name CertGetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, alias, &propLen);
// add to list of aliases AddDataToList(&list, alias, strlen(alias)+1); } return jaliases; }
列表5
方法chooseClientAlias()和chooseServerAlias()从一列别名中返回一个客户端(或服务器)别名。如果只有一个别名,在选择别名时就不会有歧义。因为Java的创始人对于选择运用哪个别名并没有提供任何特殊的指导,我就选择了清单中第一个别名。另一个选择合适的客户端别名的方法就是提示用户从一列可能的别名中选择一个别名。(在SSL客户端,你通常可以这么做,但在服务器上不行。)
KeyManager的getCertificateChain()方法为一个证书返回有序的证书链。该方法通过调用getAcceptedIssuers()方法得到一列可信任的证书签发者。首先我们找到证书签发者的Distinguished Name(DN),然后我们查看是否有哪个可信任的签发者有那个DN。几个签发者可以有同一个DN。对于具有签发者DN的每个证书,我们提取公钥并尝试在原始证书上确认签名。如果没有一个签发者有正确的DN和正确的公钥,证书链就被破坏了,出现一个异常。如果我们找到了正确的签发者签发的证书,我们就重复上述过程来查找和确认那个证书的签发者。重复该过程,直到我们达到根CA。对于一个根CA,Subject DN和签发者DN是一样的(见列表6)。
方法getCertChain()为一个证书返回有序的证书链。 MSCryptoFunctions MSF = new MSCryptoFunctions(); X509Certificate[] getCertChain( X509Certificate cert) { try { getCACerts();
Principal subject = cert.getSubjectDN(); Principal issuer = cert.getIssuerDN(); CertChainList.add(cert);
// stop if issuer==subject (root CA) while (!(issuer.equals(subject))) {
match = false; X509CertSelector xcs = new X509CertSelector(); xcs.setCertificateValid(new Date());
Collection certcollection = CACerts.getCertificates(xcs);
// // the next 7 lines are inserted to work // around a problem with X509CertSelector. // we should be able to do this with // xcs.setSubject(issuer.toString()); // Iterator iter = certcollection.iterator(); while ( iter.hasNext() ) { X509Certificate cacert = (X509Certificate) (iter.next()); if (!cacert.getSubjectDN().equals(issuer)) iter.remove(); }
issuerArray = new X509Certificate[ certcollection.size()]; issuerArray = (X509Certificate[]) certcollection.toArray(issuerArray);
for (int i=0; i<\<>issuerArray.length; i++) if (verifySignature(issuerArray[i], cert)){ match = true; cert = issuerArray[i]; subject = cert.getSubjectDN(); issuer = cert.getIssuerDN(); CertChainList.add(cert); break; } if (!match) { return null; // cert chain broken } } } catch (Exception e) { e.printStackTrace(); }
X509Certificate[] CertChain = new X509Certificate[CertChainList.size()]; CertChainList.toArray(CertChain);
return CertChain; }
getPrivateKey()方法为一个别名返回私钥,假设私钥可以从Microsoft钥匙库中输出。记住,有时私钥是不能输出的。(例如,如果你用了一个加密了的智能卡,那么就没人可以从智能卡上读取私钥了。)如果不能输出私钥,getPrivateKey()就返回一个虚拟的私钥。所以,如果getPrivateKey()不能得到私钥,我们就骗Java,让它认为得到了私钥。getPrivateKey()也缓存别名,所以,当一个Java程序试图执行一个RSA数字签名函数时,我们就会知道运用哪个私钥了(缓存的别名),而且Microsoft加密提供者就可以执行我们想要的RSA签名或解密函数了(见列表7)。
方法getPrivateKey()为一个别名返回私钥,假设私钥可以从Windows钥匙库中输出。 MSCryptoFunctions MSF = new MSCryptoFunctions(); public PrivateKey getPrivateKey(String alias) { // get the private key from MS Windows for // this alias byte[] keyblob = MSF.MSgetPrivateKey(alias);
if (keyblob == null) { // generate a dummy key byte[] modblob = new byte[128]; for(i=0; i<128; i++) modblob[i] = 127; mod = new BigInteger(modblob); exp = mod;
} else { // use the key that got exported for(i=0; i modblob[i] = keyblob[19-i+(keysize/16)*2]; expblob[i] = keyblob[19-i+(keysize/16)*9]; } mod = new BigInteger(1, modblob); exp = new BigInteger(1, expblob); } RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(mod, exp); KeyFactory kf = KeyFactory.getInstance("RSA"); privkey = kf.generatePrivate(privKeySpec); return privkey; }
|