PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/vavi-crypt-sandbox/src/main/java/com/boyter/mscrypto/MSKeyManagerImpl.java

http://umjammer.googlecode.com/
Java | 372 lines | 241 code | 63 blank | 68 comment | 32 complexity | 1e2ab59030d186d93e12baded3587a69 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1
  1. /*
  2. * Copyright (c) 2001 Brian Boyter
  3. * All rights reserved
  4. *
  5. * This software is released subject to the GNU Public License. See
  6. * the full license included with this distribution.
  7. */
  8. package com.boyter.mscrypto;
  9. import java.io.ByteArrayInputStream;
  10. import java.io.IOException;
  11. import java.math.BigInteger;
  12. import java.net.Socket;
  13. import java.security.GeneralSecurityException;
  14. import java.security.KeyFactory;
  15. import java.security.KeyStore;
  16. import java.security.KeyStoreException;
  17. import java.security.Principal;
  18. import java.security.PrivateKey;
  19. import java.security.cert.CertificateFactory;
  20. import java.security.cert.X509Certificate;
  21. import java.security.interfaces.RSAPrivateCrtKey;
  22. import java.security.interfaces.RSAPrivateKey;
  23. import java.security.spec.RSAPrivateCrtKeySpec;
  24. import java.security.spec.RSAPrivateKeySpec;
  25. import java.util.ArrayList;
  26. import java.util.Arrays;
  27. import java.util.Iterator;
  28. import java.util.List;
  29. import java.util.logging.Level;
  30. import javax.net.ssl.X509KeyManager;
  31. import com.boyter.mscrypto.MSCryptoManager.Flag;
  32. import vavi.util.Debug;
  33. /**
  34. * MSKeyManagerImpl.
  35. *
  36. * @author Brian Boyter
  37. * @author <a href="mailto:vavivavi@yahoo.co.jp">Naohide Sano</a> (nsano)
  38. * @version 0.00 050314 nsano modified <br>
  39. */
  40. final class MSKeyManagerImpl implements X509KeyManager {
  41. /**
  42. * @param ks use windows key store, so this means nothing, set null
  43. * @param passphrase use windows key store, so this means nothing, set null
  44. */
  45. MSKeyManagerImpl(KeyStore ks, char[] passphrase) throws KeyStoreException {
  46. }
  47. /** native interface */
  48. private static final MSCryptoManager msCryptoManager = MSCryptoManager.getInstance();
  49. /**
  50. * Choose an alias to authenticate the client side of a secure socket given
  51. * the public key type and the list of certificate issuer authorities
  52. * recognized by the peer (if any).
  53. */
  54. public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
  55. String alias = null;
  56. Debug.println(">>>> chooseClientAlias: entered: issures: " + issuers.length + ", types: " + keyType.length);
  57. try {
  58. List<String> aliases = new ArrayList<String>();
  59. for (int i = 0; i < keyType.length; i++) {
  60. Debug.println(i + ": " + keyType[i]);
  61. String[] tmp = getClientAliases(keyType[i], issuers);
  62. aliases.addAll(Arrays.asList(tmp));
  63. }
  64. if (aliases.size() == 0) {
  65. Debug.println("chooseClientAlias: something wrong - no aliases");
  66. return null;
  67. }
  68. Debug.println("aliases: " + aliases.size());
  69. alias = aliases.get(0);
  70. } catch (Exception e) {
  71. throw (RuntimeException) new IllegalStateException().initCause(e);
  72. }
  73. Debug.println("<<<< chooseClientAlias: " + alias);
  74. return alias;
  75. }
  76. /**
  77. * Choose an alias to authenticate the server side of a secure socket given
  78. * the public key type and the list of certificate issuer authorities
  79. * recognized by the peer (if any).
  80. */
  81. public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
  82. String alias = null;
  83. Debug.println(">>>> chooseServerAlias: return server alias");
  84. try {
  85. String[] aliases = getServerAliases(keyType, issuers);
  86. if (aliases == null) {
  87. Debug.println("chooseServerAlias: something wrong - no aliases");
  88. return null;
  89. }
  90. alias = aliases[0];
  91. } catch (Exception e) {
  92. throw (RuntimeException) new IllegalStateException().initCause(e);
  93. }
  94. Debug.println("<<<< chooseServerAlias: " + alias);
  95. return alias;
  96. }
  97. /**
  98. * Returns the certificate chain to validate the given alias.
  99. */
  100. public X509Certificate[] getCertificateChain(String alias) {
  101. Debug.println(">>>> getCertificateChain: entered, alias:" + alias);
  102. X509Certificate[] certChain = null;
  103. X509Certificate cert = null;
  104. try {
  105. byte[] certBlob = msCryptoManager.getCert("My", alias);
  106. CertificateFactory cf = CertificateFactory.getInstance("X.509");
  107. ByteArrayInputStream bais = new ByteArrayInputStream(certBlob);
  108. cert = (X509Certificate) cf.generateCertificate(bais);
  109. bais.close();
  110. certChain = msCryptoManager.getCertChain(cert);
  111. } catch (Exception e) {
  112. throw (RuntimeException) new IllegalStateException().initCause(e);
  113. }
  114. Debug.println("<<<< getCertificateChain: certChain:" + (certChain != null ? certChain.length : -1));
  115. return certChain;
  116. }
  117. /**
  118. * Get the matching aliases for authenticating the client side of a secure
  119. * socket given the public key type and the list of certificate issuer
  120. * authorities recognized by the peer (if any).
  121. */
  122. public String[] getClientAliases(String keyType, Principal[] issuers) {
  123. Debug.println(">>>> getClientAliases: entered: " + keyType);
  124. String[] validAliases = null;
  125. try {
  126. String[] aliases = msCryptoManager.getAliases("My");
  127. if (aliases == null) {
  128. throw new IllegalStateException("No client aliases found");
  129. }
  130. // now throw out any aliases not signed by an approved issuer,
  131. // expired, or revoked
  132. Debug.println("Number of accepted issuers: " + (issuers != null ? issuers.length : -1));
  133. validAliases = checkAlias(aliases, issuers);
  134. } catch (Exception e) {
  135. throw (RuntimeException) new IllegalStateException().initCause(e);
  136. }
  137. Debug.println("<<<< aliases found: " + validAliases.length);
  138. for (int i = 0; i < validAliases.length; i++) {
  139. Debug.println("getClientAliases: alias: " + validAliases[i]);
  140. }
  141. return validAliases;
  142. }
  143. /**
  144. * Get the matching aliases for authenticating the server side of a secure
  145. * socket given the public key type and the list of certificate issuer
  146. * authorities recognized by the peer (if any).
  147. */
  148. public String[] getServerAliases(String keyType, Principal[] issuers) {
  149. Debug.println("<<<< getServerAliases: return array of aliases ");
  150. String[] validAliases = null;
  151. try {
  152. String[] aliases = msCryptoManager.getAliases("My");
  153. if (aliases == null) {
  154. Debug.println(">>>> No server aliases found");
  155. return null;
  156. }
  157. // now throw out any aliases not signed by an approved issuer,
  158. // expired, or revoked
  159. validAliases = checkAlias(aliases, issuers);
  160. } catch (Exception e) {
  161. throw (RuntimeException) new IllegalStateException().initCause(e);
  162. }
  163. Debug.println(">>>> aliases found: " + validAliases.length);
  164. for (int i = 0; i < validAliases.length; i++) {
  165. Debug.println("getServerAliases: alias: " + validAliases[i]);
  166. }
  167. return validAliases;
  168. }
  169. /**
  170. * returns the RSA private key for the given alias
  171. */
  172. public PrivateKey getPrivateKey(String alias) {
  173. RSAPrivateKey rsaprivkey = null;
  174. RSAPrivateCrtKey rsaprivcrtkey = null;
  175. BigInteger mod = null;
  176. BigInteger exp = null;
  177. BigInteger coeff = null;
  178. BigInteger p = null;
  179. BigInteger q = null;
  180. BigInteger expp = null;
  181. BigInteger expq = null;
  182. BigInteger pubExp = null;
  183. byte[] pubExpBlob = new byte[4];
  184. byte[] keySizeBlob = new byte[4];
  185. int keySize;
  186. Debug.println("<<<< getPrivateKey: entered, alias: " + alias);
  187. try {
  188. byte[] keyblob = msCryptoManager.getPrivateKey(alias);
  189. KeyFactory kf = KeyFactory.getInstance("RSA");
  190. if (keyblob == null) { // generate a dummy key
  191. byte[] modblob = new byte[128];
  192. for (int i = 0; i < 128; i++) {
  193. modblob[i] = 127;
  194. }
  195. mod = new BigInteger(modblob);
  196. exp = mod;
  197. RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(mod, exp);
  198. rsaprivkey = (RSAPrivateKey) kf.generatePrivate(privKeySpec);
  199. Debug.println("getPrivateKey: normal exit");
  200. return rsaprivkey;
  201. } else { // use the key that got exported
  202. for (int i = 0; i < 4; i++) {
  203. pubExpBlob[i] = keyblob[19 - i];
  204. keySizeBlob[i] = keyblob[15 - i];
  205. }
  206. BigInteger bigKeySize = new BigInteger(keySizeBlob);
  207. keySize = bigKeySize.intValue();
  208. Debug.println("keysize: " + keySize);
  209. byte[] modBlob = new byte[(keySize / 8)];
  210. byte[] expBlob = new byte[(keySize / 8)];
  211. byte[] pBlob = new byte[keySize / 16];
  212. byte[] qBlob = new byte[keySize / 16];
  213. byte[] exppBlob = new byte[keySize / 16];
  214. byte[] expqBlob = new byte[keySize / 16];
  215. byte[] coefBlob = new byte[keySize / 16];
  216. for (int i = 0; i < keySize / 8; i++) {
  217. modBlob[i] = keyblob[19 - i + (keySize / 16) * 2];
  218. expBlob[i] = keyblob[19 - i + (keySize / 16) * 9];
  219. }
  220. for (int i = 0; i < keySize / 16; i++) {
  221. pBlob[i] = keyblob[19 - i + (keySize / 16) * 3];
  222. qBlob[i] = keyblob[19 - i + (keySize / 16) * 4];
  223. exppBlob[i] = keyblob[19 - i + (keySize / 16) * 5];
  224. expqBlob[i] = keyblob[19 - i + (keySize / 16) * 6];
  225. coefBlob[i] = keyblob[19 - i + (keySize / 16) * 7];
  226. }
  227. mod = new BigInteger(1, modBlob);
  228. exp = new BigInteger(1, expBlob);
  229. coeff = new BigInteger(1, coefBlob);
  230. p = new BigInteger(1, pBlob);
  231. q = new BigInteger(1, qBlob);
  232. expp = new BigInteger(1, exppBlob);
  233. expq = new BigInteger(1, expqBlob);
  234. pubExp = new BigInteger(1, pubExpBlob);
  235. RSAPrivateCrtKeySpec privCrtKeySpec = new RSAPrivateCrtKeySpec(mod, pubExp, exp, p, q, expp, expq, coeff);
  236. rsaprivcrtkey = (RSAPrivateCrtKey) kf.generatePrivate(privCrtKeySpec);
  237. }
  238. } catch (Exception e) {
  239. Debug.println(Level.SEVERE, ">>>> " + e);
  240. // throw (RuntimeException) new IllegalStateException().initCause(e);
  241. }
  242. // Debug.println("mod: " + rsaprivcrtkey.getModulus());
  243. // Debug.println("pubexp: " + rsaprivcrtkey.getPublicExponent());
  244. // Debug.println("privexp: " + rsaprivcrtkey.getPrivateExponent());
  245. // Debug.println("p: " + rsaprivcrtkey.getPrimeP());
  246. // Debug.println("q: " + rsaprivcrtkey.getPrimeQ());
  247. // Debug.println("expp: " + rsaprivcrtkey.getPrimeExponentP());
  248. // Debug.println("expq: " + rsaprivcrtkey.getPrimeExponentQ());
  249. // Debug.println("coeff: " + rsaprivcrtkey.getCrtCoefficient());
  250. if (rsaprivcrtkey != null) {
  251. Debug.println(">>>> getPrivateKey: normal exit");
  252. }
  253. return rsaprivcrtkey;
  254. }
  255. /**
  256. * remove any aliases not signed by an approved issuer,
  257. * expired, or revoked
  258. * @throws GeneralSecurityException
  259. * @throws IOException
  260. */
  261. private static String[] checkAlias(String[] aliases, Principal[] issuers) throws GeneralSecurityException, IOException {
  262. Debug.println(">>>> CheckAlias: entered");
  263. X509Certificate cert = null;
  264. List<String> aliasList = new ArrayList<String>();
  265. List<String> issuerList = new ArrayList<String>();
  266. Debug.println("aliases: " + aliases.length);
  267. Debug.println("issuers: " + (issuers != null ? issuers.length : -1));
  268. for (int i = 0; i < aliases.length; i++) {
  269. aliasList.add(aliases[i]);
  270. }
  271. if (issuers != null) {
  272. for (int i = 0; i < issuers.length; i++) {
  273. issuerList.add(issuers[i].toString());
  274. }
  275. }
  276. // iterate thru the list of aliases
  277. Iterator<String> iter = aliasList.iterator();
  278. while (iter.hasNext()) {
  279. String alias = iter.next();
  280. // get the cert for this alias
  281. byte[] certBlob = msCryptoManager.getCert("My", alias);
  282. CertificateFactory cf = CertificateFactory.getInstance("X.509");
  283. ByteArrayInputStream input = new ByteArrayInputStream(certBlob);
  284. cert = (X509Certificate) cf.generateCertificate(input);
  285. input.close();
  286. // is this alias's cert signed by an approved issuer?
  287. if (issuerList.size() != 0) {
  288. String certIssuer = cert.getIssuerDN().toString();
  289. Debug.println("CheckAlias: certIssuer: " + certIssuer);
  290. if (!issuerList.contains(certIssuer)) {
  291. iter.remove();
  292. Debug.println("CheckAlias: no issuer found for alias " + alias);
  293. continue;
  294. }
  295. }
  296. if (!msCryptoManager.isCertValid(cert, Flag.AcceptTheCertAnyway)) {
  297. iter.remove();
  298. Debug.println("CheckAlias: cert is expired or revoked for alias " + alias);
  299. continue;
  300. }
  301. Debug.println("CheckAlias: alias is valid " + alias);
  302. }
  303. aliases = new String[aliasList.size()];
  304. aliasList.toArray(aliases);
  305. Debug.println("<<<< CheckAlias: valid aliases: " + aliases.length);
  306. return aliases;
  307. }
  308. }
  309. /* */