Changeset 3232 for branches/2.2/security/ExpressoCert/src/br/gov/serpro/cert/DigitalCertificate.java
- Timestamp:
- 09/13/10 15:01:56 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2/security/ExpressoCert/src/br/gov/serpro/cert/DigitalCertificate.java
r1174 r3232 56 56 import br.gov.serpro.util.Base64Utils; 57 57 import com.sun.mail.util.BASE64DecoderStream; 58 import java.io.InputStreamReader; 59 import java.io.OutputStream; 60 import java.io.OutputStreamWriter; 61 import java.io.PipedInputStream; 62 import java.io.PipedOutputStream; 58 63 import java.security.AlgorithmParameters; 64 import javax.activation.CommandMap; 65 import javax.activation.MailcapCommandMap; 59 66 import javax.mail.BodyPart; 67 import javax.mail.internet.ContentType; 68 import javax.mail.internet.MimeUtility; 69 import javax.mail.internet.PreencodedMimeBodyPart; 60 70 import org.bouncycastle.asn1.ASN1InputStream; 61 71 import org.bouncycastle.asn1.DERObject; … … 71 81 * @author Mário César Kolling - mario.kolling@serpro.gov.br 72 82 */ 73 74 83 //TODO: Criar exceções para serem lançadas, entre elas DigitalCertificateNotLoaded 75 84 //TODO: Adicionar setup 76 77 85 public class DigitalCertificate { 78 86 79 87 private TokenCollection tokens; 80 private Certificate cert; // Certificado extraído da KeyStore. Pode ser nulo. 81 private KeyStore keyStore; // KeyStore que guarda o certificado do usuário. Pode ser nulo. 82 83 private Frame parentFrame; 88 private Certificate cert; // Certificado extraído da KeyStore. Pode ser nulo. 89 private KeyStore keyStore; // KeyStore que guarda o certificado do usuário. Pode ser nulo. 90 private Frame parentFrame; 84 91 private Setup setup; 85 86 // TODO: Transformar pkcs12Input em uma string ou URL com o caminho para a KeyStore pkcs12 87 private FileInputStream pkcs12Input; // stream da KeyStore pkcs12. Pode ser nulo. 88 private String providerName; // Nome do SecurityProvider pkcs11 carregado. Pode ser nulo. 89 private String hostAddress; // Endereço do host, onde a página principal do 90 91 private static final String HOME_SUBDIR; // Subdiretório dentro do diretório home do usuário. Dependente de SO. 92 private static final String EPASS_2000; // Caminho da biblioteca do token ePass2000. Dependente de SO. 93 94 private static final String CRLF = "\r\n"; // Separa campos na resposta do serviço de verificação de certificados 95 private static final String SUBJECT_ALTERNATIVE_NAME = "2.5.29.17"; // Não é mais utilizado. 96 private static final URL[] TRUST_STORES_URLS = new URL[3]; // URLs (file:/) das TrustStores, cacerts (jre), 97 // trusted.certs e trusted.jssecerts (home do usuário) 98 // Utilizadas para validação do certificado do servidor. 99 private static final String[] TRUST_STORES_PASSWORDS = null; // Senhas para cada uma das TrustStores, 100 // caso seja necessário. 101 private int keystoreStatus; 102 public static final int KEYSTORE_DETECTED = 0; 103 public static final int KEYSTORE_NOT_DETECTED = 1; 104 public static final int KEYSTORE_ALREADY_LOADED = 2; 105 106 /* 107 * Bloco estático que define os caminhos padrões da instalação da jre, 108 * do diretório home do usuário, e da biblioteca de sistema do token ePass2000, 109 * de acordo com o sistema operacional. 92 // TODO: Transformar pkcs12Input em uma string ou URL com o caminho para a KeyStore pkcs12 93 private FileInputStream pkcs12Input; // stream da KeyStore pkcs12. Pode ser nulo. 94 private String providerName; // Nome do SecurityProvider pkcs11 carregado. Pode ser nulo. 95 private String hostAddress; // Endereço do host, onde a página principal do 96 private static final String HOME_SUBDIR; // Subdiretório dentro do diretório home do usuário. Dependente de SO. 97 private static final String EPASS_2000; // Caminho da biblioteca do token ePass2000. Dependente de SO. 98 private static final String CRLF = "\r\n"; // Separa campos na resposta do serviço de verificação de certificados 99 private static final String SUBJECT_ALTERNATIVE_NAME = "2.5.29.17"; // Não é mais utilizado. 100 private static final URL[] TRUST_STORES_URLS = new URL[3]; // URLs (file:/) das TrustStores, cacerts (jre), 101 // trusted.certs e trusted.jssecerts (home do usuário) 102 // Utilizadas para validação do certificado do servidor. 103 private static final String[] TRUST_STORES_PASSWORDS = null; // Senhas para cada uma das TrustStores, 104 // caso seja necessário. 105 private int keystoreStatus; 106 public static final int KEYSTORE_DETECTED = 0; 107 public static final int KEYSTORE_NOT_DETECTED = 1; 108 public static final int KEYSTORE_ALREADY_LOADED = 2; 109 110 /* 111 * Bloco estático que define os caminhos padrões da instalação da jre, 112 * do diretório home do usuário, e da biblioteca de sistema do token ePass2000, 113 * de acordo com o sistema operacional. 114 */ 115 static { 116 117 Properties systemProperties = System.getProperties(); 118 Map<String, String> env = System.getenv(); 119 120 /* TODO: Testar a existência de vários drivers de dispositivos. Determinar qual deve ser utilizado 121 * e guardar em uma property no subdiretório home do usuário. 110 122 */ 111 static { 112 113 Properties systemProperties = System.getProperties(); 114 Map<String, String> env = System.getenv(); 115 116 /* TODO: Testar a existência de vários drivers de dispositivos. Determinar qual deve ser utilizado 117 * e guardar em uma property no subdiretório home do usuário. 118 */ 119 120 if (systemProperties.getProperty("os.name").equalsIgnoreCase("linux")){ 121 HOME_SUBDIR = "/.java/deployment/security"; 122 EPASS_2000 = "/usr/lib/libepsng_p11.so"; 123 } 124 else { 125 HOME_SUBDIR = "\\dados de aplicativos\\sun\\java\\deployment\\security"; 126 EPASS_2000 = System.getenv("SystemRoot")+"\\system32\\ngp11v211.dll"; 127 //EPASS_2000 = System.getenv("ProgramFiles")+"\\Gemplus\\GemSafe Libraries\\BIN\\gclib.dll"; 128 } 129 130 try { 131 if (systemProperties.getProperty("os.name").equalsIgnoreCase("linux")){ 132 TRUST_STORES_URLS[0] = new File(systemProperties.getProperty("java.home") 133 + "/lib/security/cacerts").toURI().toURL(); 134 TRUST_STORES_URLS[1] = new File(systemProperties.getProperty("user.home") 135 + HOME_SUBDIR + "/trusted.certs").toURI().toURL(); 136 TRUST_STORES_URLS[2] = new File(systemProperties.getProperty("user.home") 137 + HOME_SUBDIR + "/trusted.jssecerts").toURI().toURL(); 138 } else { 139 140 TRUST_STORES_URLS[0] = new File(systemProperties.getProperty("java.home") + 141 "\\lib\\security\\cacerts").toURI().toURL(); 142 TRUST_STORES_URLS[1] = new File(systemProperties.getProperty("user.home") + 143 HOME_SUBDIR + "\\trusted.certs").toURI().toURL(); 144 TRUST_STORES_URLS[2] = new File(systemProperties.getProperty("user.home") + 145 HOME_SUBDIR + "\\trusted.jssecerts").toURI().toURL(); 146 } 147 148 149 } catch (MalformedURLException e) { 150 e.printStackTrace(); 151 } 152 } 153 154 /** 155 * 156 */ 157 public DigitalCertificate() { 158 this.hostAddress = null; 159 this.parentFrame = null; 160 } 161 162 /** 163 * Construtor da classe. Recebe a {@link URL} da página em que a Applet está incluída. 164 * @param pageAddress URL da página em que a Applet está incluída 165 */ 166 private DigitalCertificate(URL pageAddress){ 167 this.hostAddress = pageAddress.getHost(); 168 this.parentFrame = null; 169 } 170 171 private DigitalCertificate(Frame parent){ 172 this.hostAddress = null; 173 this.parentFrame = parent; 174 } 175 176 177 public DigitalCertificate(Frame parent, Setup setup){ 178 this(parent); 179 this.setup = setup; 180 } 181 182 public DigitalCertificate(URL pageAddress, Setup setup){ 183 this(pageAddress); 184 this.setup = setup; 185 } 186 187 /** 188 * Destrói a Applet, removendo o security provider inicializado se o atributo providerName 189 * for diferente de nulo. 190 */ 191 public void destroy(){ 192 193 AuthProvider ap = null; 194 195 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 196 System.out.println("logout no provider"); 197 } 198 if (keyStore != null){ 199 ap = (AuthProvider) this.keyStore.getProvider(); 200 } 201 202 if (ap != null){ 203 try { 204 ap.logout(); 205 } catch (LoginException e) { 206 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 207 e.printStackTrace(); 208 } 209 } 210 } 211 212 if (providerName != null){ 213 Security.removeProvider(providerName); 214 } 215 216 this.cert = null; 217 this.keyStore = null; 218 this.hostAddress = null; 219 this.pkcs12Input = null; 220 this.providerName = null; 221 222 } 223 224 /** 225 * Procura pelo token nos locais padrões (Por enquanto só suporta o token ePass200), 226 * senão procura por um certificado A1 em System.getProperties().getProperty("user.home") + 227 * HOME_SUBDIR + "/trusted.clientcerts" e retorna um inteiro de acordo com resultado desta procura. 228 * 229 * @author Mário César Kolling 230 * @return Retorna um destes valores inteiros DigitalCertificate.KEYSTORE_DETECTED, 231 * DigitalCertificate.KEYSTORE_ALREADY_LOADED ou DigitalCertificate.KEYSTORE_NOT_DETECTED 232 * @see DigitalCertificate 233 */ 234 public int init(){ 235 236 // TODO: Usar dentro de um "loop" para testar outros modelos de tokens. 237 this.tokens = new TokenCollection(setup); 238 int interfaceType = DigitalCertificate.KEYSTORE_DETECTED; 239 240 try 241 { 242 // Tenta abrir o Token padrï¿œo (ePass2000). 243 loadKeyStore(); 244 245 } 246 catch (Exception e1){ 247 248 Provider[] providers = Security.getProviders(); 249 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 250 for (Provider provider: providers){ 251 System.out.println(provider.getInfo()); 252 } 253 254 // Não conseguiu abrir o token (ePass2000). 255 System.out.println("Erro ao ler o token: " + e1.getMessage()); 256 } 257 258 try 259 { 260 // Tenta abrir a keyStore padrão 261 // USER_HOME/deployment/security/trusted.clientcerts 262 263 Properties props = System.getProperties(); 264 pkcs12Input = new FileInputStream(props.getProperty("user.home") + HOME_SUBDIR + "/trusted.clientcerts"); 265 266 // Se chegar aqui significa que arquivo de KeyStore existe. 267 keyStore = KeyStore.getInstance("JKS"); 268 269 } 270 catch (Exception ioe){ 271 // Não conseguiu abrir a KeyStore pkcs12 272 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 273 System.out.println(ioe.getMessage()); 274 } 275 } 276 } 277 278 279 if (keyStore == null){ 280 // Não conseguiu inicializar a KeyStore. Mostra tela de login com usuário e senha. 281 this.keystoreStatus = DigitalCertificate.KEYSTORE_NOT_DETECTED; 282 //} else if (keyStore.getType().equalsIgnoreCase("pkcs11")){ 123 124 if (systemProperties.getProperty("os.name").equalsIgnoreCase("linux")) { 125 HOME_SUBDIR = "/.java/deployment/security"; 126 EPASS_2000 = "/usr/lib/libepsng_p11.so"; 127 } else { 128 HOME_SUBDIR = "\\dados de aplicativos\\sun\\java\\deployment\\security"; 129 EPASS_2000 = System.getenv("SystemRoot") + "\\system32\\ngp11v211.dll"; 130 //EPASS_2000 = System.getenv("ProgramFiles")+"\\Gemplus\\GemSafe Libraries\\BIN\\gclib.dll"; 131 } 132 133 try { 134 if (systemProperties.getProperty("os.name").equalsIgnoreCase("linux")) { 135 TRUST_STORES_URLS[0] = new File(systemProperties.getProperty("java.home") + "/lib/security/cacerts").toURI().toURL(); 136 TRUST_STORES_URLS[1] = new File(systemProperties.getProperty("user.home") + HOME_SUBDIR + "/trusted.certs").toURI().toURL(); 137 TRUST_STORES_URLS[2] = new File(systemProperties.getProperty("user.home") + HOME_SUBDIR + "/trusted.jssecerts").toURI().toURL(); 138 } else { 139 140 TRUST_STORES_URLS[0] = new File(systemProperties.getProperty("java.home") + 141 "\\lib\\security\\cacerts").toURI().toURL(); 142 TRUST_STORES_URLS[1] = new File(systemProperties.getProperty("user.home") + 143 HOME_SUBDIR + "\\trusted.certs").toURI().toURL(); 144 TRUST_STORES_URLS[2] = new File(systemProperties.getProperty("user.home") + 145 HOME_SUBDIR + "\\trusted.jssecerts").toURI().toURL(); 146 } 147 148 // Define os tipos smime no mailcap 149 MailcapCommandMap mailcap = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); 150 151 mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature"); 152 mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime"); 153 mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature"); 154 mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime"); 155 mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed"); 156 157 CommandMap.setDefaultCommandMap(mailcap); 158 159 160 161 } catch (MalformedURLException e) { 162 e.printStackTrace(); 163 } 164 } 165 166 /** 167 * 168 */ 169 public DigitalCertificate() { 170 this.hostAddress = null; 171 this.parentFrame = null; 172 } 173 174 /** 175 * Construtor da classe. Recebe a {@link URL} da página em que a Applet está incluída. 176 * @param pageAddress URL da página em que a Applet está incluída 177 */ 178 private DigitalCertificate(URL pageAddress) { 179 this.hostAddress = pageAddress.getHost(); 180 this.parentFrame = null; 181 } 182 183 private DigitalCertificate(Frame parent) { 184 this.hostAddress = null; 185 this.parentFrame = parent; 186 } 187 188 public DigitalCertificate(Frame parent, Setup setup) { 189 this(parent); 190 this.setup = setup; 191 } 192 193 public DigitalCertificate(URL pageAddress, Setup setup) { 194 this(pageAddress); 195 this.setup = setup; 196 } 197 198 public KeyStore getKeyStore() { 199 return keyStore; 200 } 201 202 public int getKeystoreStatus() { 203 return keystoreStatus; 204 } 205 206 public String getProviderName() { 207 return providerName; 208 } 209 210 /** 211 * Destrói a Applet, removendo o security provider inicializado se o atributo providerName 212 * for diferente de nulo. 213 */ 214 public void destroy() { 215 216 AuthProvider ap = null; 217 218 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 219 System.out.println("logout no provider"); 220 } 221 if (keyStore != null) { 222 ap = (AuthProvider) this.keyStore.getProvider(); 223 } 224 225 if (ap != null) { 226 try { 227 ap.logout(); 228 } catch (LoginException e) { 229 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 230 e.printStackTrace(); 231 } 232 } 233 } 234 235 if (providerName != null) { 236 Security.removeProvider(providerName); 237 } 238 239 this.cert = null; 240 this.keyStore = null; 241 this.hostAddress = null; 242 this.pkcs12Input = null; 243 this.providerName = null; 244 245 } 246 247 /** 248 * Procura pelo token nos locais padrões (Por enquanto só suporta o token ePass200), 249 * senão procura por um certificado A1 em System.getProperties().getProperty("user.home") + 250 * HOME_SUBDIR + "/trusted.clientcerts" e retorna um inteiro de acordo com resultado desta procura. 251 * 252 * @author Mário César Kolling 253 * @return Retorna um destes valores inteiros DigitalCertificate.KEYSTORE_DETECTED, 254 * DigitalCertificate.KEYSTORE_ALREADY_LOADED ou DigitalCertificate.KEYSTORE_NOT_DETECTED 255 * @see DigitalCertificate 256 */ 257 public int init() { 258 259 // TODO: Usar dentro de um "loop" para testar outros modelos de tokens. 260 this.tokens = new TokenCollection(setup); 261 int interfaceType = DigitalCertificate.KEYSTORE_DETECTED; 262 263 try { 264 // Tenta abrir o Token padrï¿œo (ePass2000). 265 loadKeyStore(); 266 267 } catch (Exception e1) { 268 269 Provider[] providers = Security.getProviders(); 270 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 271 for (Provider provider : providers) { 272 System.out.println(provider.getInfo()); 273 } 274 275 // Não conseguiu abrir o token (ePass2000). 276 System.out.println("Erro ao ler o token: " + e1.getMessage()); 277 } 278 279 try { 280 // Tenta abrir a keyStore padrão 281 // USER_HOME/deployment/security/trusted.clientcerts 282 283 Properties props = System.getProperties(); 284 pkcs12Input = new FileInputStream(props.getProperty("user.home") + HOME_SUBDIR + "/trusted.clientcerts"); 285 286 // Se chegar aqui significa que arquivo de KeyStore existe. 287 keyStore = KeyStore.getInstance("JKS"); 288 289 } catch (Exception ioe) { 290 // Não conseguiu abrir a KeyStore pkcs12 291 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 292 System.out.println(ioe.getMessage()); 293 } 294 } 295 } 296 297 298 if (keyStore == null) { 299 // Não conseguiu inicializar a KeyStore. Mostra tela de login com usuário e senha. 300 this.keystoreStatus = DigitalCertificate.KEYSTORE_NOT_DETECTED; 301 //} else if (keyStore.getType().equalsIgnoreCase("pkcs11")){ 302 } else { 303 // Usa certificado digital. 304 try { 305 // Testa se uma keystore já foi carregada previamente 306 if (keyStore.getType().equalsIgnoreCase("pkcs11")) { 307 keyStore.load(null, null); 283 308 } else { 284 // Usa certificado digital. 285 try { 286 // Testa se uma keystore já foi carregada previamente 287 if (keyStore.getType().equalsIgnoreCase("pkcs11")){ 288 keyStore.load(null, null); 289 } else { 290 keyStore.load(pkcs12Input, null); 291 } 292 293 // Se chegou aqui KeyStore está liberada, mostrar tela de login sem pedir o pin. 294 this.keystoreStatus = DigitalCertificate.KEYSTORE_ALREADY_LOADED; 295 296 } catch (ProviderException e) { 297 // Algum erro ocorreu, mostra tela de login com usuário e senha. 298 this.keystoreStatus = DigitalCertificate.KEYSTORE_NOT_DETECTED; 299 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 300 e.printStackTrace(); 301 } 302 } catch (IOException e){ 303 // KeyStore não está liberada, mostra tela de login com o pin. 304 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 305 System.out.println(e.getMessage()); 306 } 307 this.keystoreStatus = DigitalCertificate.KEYSTORE_DETECTED; 308 } catch (GeneralSecurityException e){ 309 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 310 e.printStackTrace(); 311 } 312 } 313 } 314 315 return keystoreStatus; 316 317 } 318 319 /** 320 * Usado para assinar digitalmente um e-mail. 321 * @param mime 322 * @return String vazia 323 */ 324 public String signMail (Map<String, String> data) throws IOException, GeneralSecurityException, SMIMEException, MessagingException{ 325 326 Key privateKey = null; 327 if (this.keystoreStatus == DigitalCertificate.KEYSTORE_DETECTED){ 328 String pin = DialogBuilder.showPinDialog(this.parentFrame, this.setup); 329 if (pin != null){ 330 openKeyStore(pin.toCharArray()); 331 privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), pin.toCharArray()); 332 } 333 else { 334 return null; 335 } 336 } 337 /* 338 else if (this.keystoreStatus == DigitalCertificate.KEYSTORE_ALREADY_LOADED){ 339 if (DialogBuilder.showPinNotNeededDialog(this.parentFrame)){ 340 openKeyStore(null); 341 privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), null); 342 } 343 else { 344 return null; 345 } 346 } 347 */ 348 else { 349 350 //DialogBuilder.showMessageDialog(this.parentFrame, "Nenhum token/smartcard foi detectado.\nOperação não pôde ser realizada!"); 351 DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate001"), this.setup); 352 return null; 353 } 354 355 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 356 357 Certificate certificate = getCert(); 358 359 KeyPair keypair = new KeyPair(certificate.getPublicKey(), (PrivateKey) privateKey); 360 361 // Cria a cadeia de certificados que a gente vai enviar 362 List certList = new ArrayList(); 363 364 certList.add(certificate); 365 366 // 367 // create the base for our message 368 // 369 String fullMsg = data.get("body"); 370 371 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 372 System.out.println("Corpo do e-mail:\n"+fullMsg+"\n"); 373 } 374 375 // 376 // Get a Session object and create the mail message 377 // 378 Properties props = System.getProperties(); 379 Session session = Session.getDefaultInstance(props, null); 380 381 InputStream is = new ByteArrayInputStream(fullMsg.getBytes("iso-8859-1")); 382 MimeMessage unsignedMessage = new MimeMessage(session, is); 383 384 // 385 // create a CertStore containing the certificates we want carried 386 // in the signature 387 // 388 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 389 System.out.println("Provider: " + providerName); 390 } 391 CertStore certsAndcrls = CertStore.getInstance( 392 "Collection", 393 new CollectionCertStoreParameters(certList), "BC"); 394 395 // 396 // create some smime capabilities in case someone wants to respond 397 // 398 ASN1EncodableVector signedAttrs = new ASN1EncodableVector(); 399 400 SMIMECapabilityVector caps = new SMIMECapabilityVector(); 401 402 caps.addCapability(SMIMECapability.dES_EDE3_CBC); 403 caps.addCapability(SMIMECapability.rC2_CBC, 128); 404 caps.addCapability(SMIMECapability.dES_CBC); 405 406 SMIMESignedGenerator gen = new SMIMESignedGenerator(unsignedMessage.getEncoding()); 407 408 gen.addSigner(keypair.getPrivate(), (X509Certificate) certificate, SMIMESignedGenerator.DIGEST_SHA1, new AttributeTable(signedAttrs), null); 409 410 gen.addCertificatesAndCRLs(certsAndcrls); 411 412 //TODO: Extrair todos os headers de unsignedMessage 413 414 // Gera a assinatura 415 Object content = unsignedMessage.getContent(); 416 417 //TODO: igualar unsignedMessage a null 418 //TODO: Pegar os headers do objeto que guardarï¿œ esses headers quando necessï¿œrio. 419 420 MimeMultipart mimeMultipartContent = null; 421 MimeBodyPart mimeBodyPartContent = new MimeBodyPart(); 422 423 if (content.getClass().getName().contains("MimeMultipart")){ 424 mimeMultipartContent = (MimeMultipart) content; 425 } 426 else { 427 is = new ByteArrayInputStream(content.toString().getBytes("iso-8859-1")); 428 mimeBodyPartContent = new MimeBodyPart(is); 429 mimeBodyPartContent.setHeader("Content-Type", unsignedMessage.getHeader("Content-Type", null)); //TODO: testar se valor existe 430 is = null; 431 } 432 content = null; 433 434 MimeBodyPart msg = null; 435 if (mimeMultipartContent == null){ 436 msg = mimeBodyPartContent; 437 mimeBodyPartContent = null; 438 } 439 else { 440 msg = new MimeBodyPart(); 441 msg.setContent(mimeMultipartContent); 442 mimeMultipartContent = null; 443 } 444 445 // 446 // extract the multipart object from the SMIMESigned object. 447 // 448 MimeMultipart mm = gen.generate(msg, providerName); 449 gen = null; 450 msg = null; 451 452 MimeMessage body = new MimeMessage(session); 453 body.setFrom(unsignedMessage.getFrom()[0]); 454 body.setRecipients(Message.RecipientType.TO, unsignedMessage.getRecipients(Message.RecipientType.TO)); 455 body.setRecipients(Message.RecipientType.CC, unsignedMessage.getRecipients(Message.RecipientType.CC)); 456 body.setRecipients(Message.RecipientType.BCC, unsignedMessage.getRecipients(Message.RecipientType.BCC)); 457 body.setSubject(unsignedMessage.getSubject(), "iso-8859-1"); 458 459 // Atrafuia o resto dos headers 460 body.setHeader("Return-Path", unsignedMessage.getHeader("Return-Path", null)); 461 body.setHeader("Message-ID", unsignedMessage.getHeader("Message-ID", null)); 462 body.setHeader("X-Priority", unsignedMessage.getHeader("X-Priority", null)); 463 body.setHeader("X-Mailer", unsignedMessage.getHeader("X-Mailer", null)); 464 body.setHeader("Disposition-Notification-To", unsignedMessage.getHeader("Disposition-Notification-To", null)); 465 body.setHeader("Date", unsignedMessage.getHeader("Date", null)); 466 body.setContent(mm, mm.getContentType()); 467 mm = null; 468 469 if (setup.getParameter("debug").equalsIgnoreCase("true")) { 470 System.out.println("\nHeaders do e-mail original:\n"); 471 } 472 473 body.saveChanges(); 474 475 ByteArrayOutputStream oStream = new ByteArrayOutputStream(); 476 477 oStream = new ByteArrayOutputStream(); 478 body.writeTo(oStream); 479 480 body = null; 481 return oStream.toString("iso-8859-1"); 482 483 } 484 485 /** 486 * Método utilizado para criptografar um e-mail 487 * @param source 488 * @return 489 */ 490 public String cipherMail(Map<String, String> data) throws IOException, GeneralSecurityException, MessagingException, CMSException, SMIMEException{ 491 492 //Pega certificado do usuário. 493 494 Key privateKey = null; 495 if (this.keystoreStatus == DigitalCertificate.KEYSTORE_DETECTED){ 496 String pin = DialogBuilder.showPinDialog(this.parentFrame, this.setup); 497 if (pin != null){ 498 openKeyStore(pin.toCharArray()); 499 privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), pin.toCharArray()); 500 } 501 else { 502 return null; 503 } 504 } 505 /* 506 else if (this.keystoreStatus == DigitalCertificate.KEYSTORE_ALREADY_LOADED){ 507 if (DialogBuilder.showPinNotNeededDialog(this.parentFrame)){ 508 openKeyStore(null); 509 privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), null); 510 } 511 else { 512 return null; 513 } 514 } 515 */ 516 else { 517 518 //DialogBuilder.showMessageDialog(this.parentFrame, "Nenhum token/smartcard foi detectado.\nOperação não pôde ser realizada!"); 519 DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate001"), this.setup); 520 return null; 521 } 522 523 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 524 525 X509Certificate cert = (X509Certificate)getCert(); 526 527 RecipientId recId = new RecipientId(); 528 recId.setSerialNumber(cert.getSerialNumber()); 529 recId.setIssuer(cert.getIssuerX500Principal()); 530 531 Properties props = System.getProperties(); 532 Session session = Session.getDefaultInstance(props, null); 533 534 String fullMsg = data.get("body"); 535 InputStream is = new ByteArrayInputStream(fullMsg.getBytes("iso-8859-1")); 536 MimeMessage encriptedMsg = new MimeMessage(session, is); 537 538 Provider prov = Security.getProvider(providerName); 539 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 540 System.out.println("Serviços do provider "+providerName+ ":\n"+ prov.getInfo()); 541 for (Provider.Service service: prov.getServices()) 542 System.out.println(service.toString() + ": " + service.getAlgorithm()); 543 } 544 545 if (setup.getParameter("debug").equalsIgnoreCase("true")) { 546 System.out.println("Email criptografado:\n" + fullMsg); 547 } 548 549 SMIMEEnvelopedParser m = new SMIMEEnvelopedParser(encriptedMsg); 550 if (setup.getParameter("debug").equalsIgnoreCase("true")) { 551 System.out.println("Algoritmo de encriptação: " + m.getEncryptionAlgOID()); 552 } 553 554 AlgorithmParameters algParams = m.getEncryptionAlgorithmParameters("BC"); 555 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 556 System.out.println("Parâmetros do algoritmo: " + algParams.toString()); 557 } 558 559 RecipientInformationStore recipients = m.getRecipientInfos(); 560 RecipientInformation recipient = recipients.get(recId); 561 562 if (recipient != null){ 563 MimeBodyPart decriptedBodyPart = SMIMEUtil.toMimeBodyPart(recipient.getContentStream(privateKey, this.providerName)); 564 encriptedMsg.setContent(decriptedBodyPart.getContent(), decriptedBodyPart.getContentType()); 565 encriptedMsg.saveChanges(); 566 567 ByteArrayOutputStream oStream = new ByteArrayOutputStream(); 568 encriptedMsg.writeTo(oStream); 569 encriptedMsg = null; 570 571 return oStream.toString("iso-8859-1"); 572 } 573 else { 574 //DialogBuilder.showMessageDialog(this.parentFrame, "Não é possível ler este e-mail com o Certificado Digital apresentado!\n" + 575 // "Motivo: Este e-mail não foi cifrado com a chave pública deste Certificado Digital."); 576 DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate002"), this.setup); 577 return null; 578 } 579 } 580 581 /** 582 * Pega as credenciais de login do dono do certificado do serviço de verificação de certificados 583 * @param pin pin para acessar o token 584 * @return resposta Array de Strings em que: 585 * Indice 0: código de retorno; 586 * Indice 1: username se código de retorno for 0, senão mensagem de erro; 587 * Indice 2: senha decriptada se código de retorno for 0, senão não existe; 588 * @throws SSLHandshakeException 589 * @throws HttpException 590 * @throws IOException 591 * @throws GeneralSecurityException 592 */ 593 public String[] getCredentials(String pin) throws SSLHandshakeException, HttpException, IOException, GeneralSecurityException{ 594 595 String[] resposta = null; 596 597 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 598 System.out.println("Proxy Configurado no browser: " + System.getProperty("http.proxyHost") 599 + ":" + System.getProperty("http.proxyPort")); 600 } 601 602 // Registra novo protocolo https, utilizando nova implementação de AuthSSLProtocolSocketFactory 603 Protocol.registerProtocol("https", new Protocol("https", 604 (ProtocolSocketFactory) new AuthSSLProtocolSocketFactory(TRUST_STORES_URLS, TRUST_STORES_PASSWORDS, this.setup), 605 443)); 606 607 HttpClient httpclient = new HttpClient(); 608 // Define um método post para o link do serviço de verificação de certificados 609 if (System.getProperty("http.proxyHost") != null && System.getProperty("http.proxyPort") != null){ 610 httpclient.getHostConfiguration().setProxy(System.getProperty("http.proxyHost"), 611 Integer.parseInt(System.getProperty("http.proxyPort"))); 612 } 613 PostMethod httppost = new PostMethod("https://"+ hostAddress + "/security/vercert.php"); 614 615 try { 616 // Adiciona parâmetro certificado no método post, executa o método, pega a resposta do servidor 617 // como uma string com CRLF de separador entre os campos e gera um array de Strings 618 httppost.addParameter("certificado", Base64Utils.der2pem(cert.getEncoded())); 619 httpclient.executeMethod(httppost); 620 resposta = httppost.getResponseBodyAsString().split(CRLF); 621 622 if (resposta.length > 2){ 623 if (Integer.parseInt(resposta[0].trim()) == 0){ 624 // Se código da resposta for zero, decripta a senha criptografada do usuário 625 resposta[2] = decriptPassword(resposta[2].trim(), pin); 626 } 627 } 628 629 } catch (IOException e){ 630 // Se for instância de SSLHandshakeException faz um cast para este tipo e lança a exceção novamente 631 // Isto é usado para diferenciar o tipo de falha, para que a mensagem para o usuário seja mostrada de 632 // acordo. 633 if (e instanceof SSLHandshakeException){ 634 throw (SSLHandshakeException) e; 635 } 636 // senão lança novamente a exceção do tipo IOException 637 throw e; 638 } finally { 639 // fecha a conexão 640 httppost.releaseConnection(); 641 } 642 643 return resposta; 644 } 645 646 /** 647 * Decripta a senha criptografada 648 * @param encodedPassword senha criptografada e codificada em base64 para ser decriptada 649 * @param pin pin para acessar a KeyStore 650 * @return decodedPassword 651 * @throws GeneralSecurityException se algum problema ocorrer na decriptação da senha. 652 */ 653 public String decriptPassword(String encodedPassword, String pin) throws GeneralSecurityException{ 654 655 String decodedPassword = new String(); 656 657 // Pega a chave privada do primeiro certificado armazenado na KeyStore 658 Enumeration<String> en = this.keyStore.aliases(); 659 String certAlias = en.nextElement(); 660 Key privateKey = this.keyStore.getKey(certAlias, pin.toCharArray()); 661 662 // Inicializa os cipher com os parâmetros corretos para realizar a decriptação 663 Cipher dcipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 664 dcipher.init(Cipher.DECRYPT_MODE, privateKey); 665 666 // Decodifica a senha em base64 e a decripta 667 decodedPassword = new String(dcipher.doFinal(Base64Utils.base64Decode(encodedPassword))); 668 669 return decodedPassword.trim(); 670 671 } 672 673 /** 674 * Carrega um novo SecurityProvider 675 * @param pkcs11Config Linha de configuração do SmartCard ou Token 676 * @throws KeyStoreException Quando não conseguir iniciar a KeyStore, ou a lib do Token 677 * ou Smartcard não foi encontrada, ou o usuário não inseriu o Token. 678 */ 679 private void loadKeyStore() throws KeyStoreException{ 680 681 //Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(pkcs11Config.getBytes())); 682 //Security.addProvider(pkcs11Provider); 683 this.keyStore = KeyStore.getInstance("PKCS11"); 684 this.providerName = keyStore.getProvider().getName(); 685 686 } 687 688 /** 689 * Abre a keystore passando o pin 690 * @param pin pin para acessar o Token 691 */ 692 public void openKeyStore(char[] pin) throws IOException{ 693 694 try { 695 696 if (this.keyStore.getType().equals("PKCS11")){ 697 this.keyStore.load(null, pin); 698 } 699 else { 700 this.keyStore.load(this.pkcs12Input, pin); 701 } 702 703 this.cert = this.keyStore.getCertificate(this.keyStore.aliases().nextElement()); 704 705 } catch (GeneralSecurityException e) { 706 if (this.setup.getParameter("debug").equalsIgnoreCase("true")){ 707 e.printStackTrace(); 708 } 709 } 710 711 } 712 713 /** 714 * @return the cert 715 */ 716 Certificate getCert() { 717 return this.cert; 718 } 719 720 /** 721 * @param cert the cert to set 722 */ 723 void setCert(Certificate cert) { 724 this.cert = cert; 725 } 726 309 keyStore.load(pkcs12Input, null); 310 } 311 312 // Se chegou aqui KeyStore está liberada, mostrar tela de login sem pedir o pin. 313 this.keystoreStatus = DigitalCertificate.KEYSTORE_ALREADY_LOADED; 314 315 } catch (ProviderException e) { 316 // Algum erro ocorreu, mostra tela de login com usuário e senha. 317 this.keystoreStatus = DigitalCertificate.KEYSTORE_NOT_DETECTED; 318 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 319 e.printStackTrace(); 320 } 321 } catch (IOException e) { 322 // KeyStore não está liberada, mostra tela de login com o pin. 323 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 324 System.out.println(e.getMessage()); 325 } 326 this.keystoreStatus = DigitalCertificate.KEYSTORE_DETECTED; 327 } catch (GeneralSecurityException e) { 328 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 329 e.printStackTrace(); 330 } 331 } 332 } 333 334 return keystoreStatus; 335 336 } 337 338 /** 339 * Usado para assinar digitalmente um e-mail. 340 * @param mime 341 * @return String vazia 342 */ 343 public String signMail(Map<String, String> data) throws IOException, GeneralSecurityException, SMIMEException, MessagingException { 344 345 Key privateKey = null; 346 if (this.keystoreStatus == DigitalCertificate.KEYSTORE_DETECTED) { 347 String pin = DialogBuilder.showPinDialog(this.parentFrame, this.setup); 348 if (pin != null) { 349 openKeyStore(pin.toCharArray()); 350 privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), pin.toCharArray()); 351 } else { 352 return null; 353 } 354 } /* 355 else if (this.keystoreStatus == DigitalCertificate.KEYSTORE_ALREADY_LOADED){ 356 if (DialogBuilder.showPinNotNeededDialog(this.parentFrame)){ 357 openKeyStore(null); 358 privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), null); 359 } 360 else { 361 return null; 362 } 363 } 364 */ else { 365 366 //DialogBuilder.showMessageDialog(this.parentFrame, "Nenhum token/smartcard foi detectado.\nOperação não pôde ser realizada!"); 367 DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate001"), this.setup); 368 return null; 369 } 370 371 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 372 373 Certificate certificate = getCert(); 374 375 KeyPair keypair = new KeyPair(certificate.getPublicKey(), (PrivateKey) privateKey); 376 377 // Cria a cadeia de certificados que a gente vai enviar 378 List certList = new ArrayList(); 379 380 certList.add(certificate); 381 382 // 383 // create the base for our message 384 // 385 String fullMsg = data.get("body"); 386 387 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 388 System.out.println("Corpo do e-mail:\n" + fullMsg + "\n"); 389 } 390 391 // 392 // Get a Session object and create the mail message 393 // 394 Properties props = System.getProperties(); 395 Session session = Session.getDefaultInstance(props, null); 396 397 InputStream is = new ByteArrayInputStream(fullMsg.getBytes("iso-8859-1")); 398 MimeMessage unsignedMessage = new MimeMessage(session, is); 399 400 // 401 // create a CertStore containing the certificates we want carried 402 // in the signature 403 // 404 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 405 System.out.println("Provider: " + providerName); 406 } 407 CertStore certsAndcrls = CertStore.getInstance( 408 "Collection", 409 new CollectionCertStoreParameters(certList), "BC"); 410 411 // 412 // create some smime capabilities in case someone wants to respond 413 // 414 ASN1EncodableVector signedAttrs = new ASN1EncodableVector(); 415 416 SMIMECapabilityVector caps = new SMIMECapabilityVector(); 417 418 caps.addCapability(SMIMECapability.dES_EDE3_CBC); 419 caps.addCapability(SMIMECapability.rC2_CBC, 128); 420 caps.addCapability(SMIMECapability.dES_CBC); 421 422 SMIMESignedGenerator gen = new SMIMESignedGenerator(unsignedMessage.getEncoding()); 423 424 //SMIMESignedGenerator gen = new SMIMESignedGenerator(); 425 426 gen.addSigner(keypair.getPrivate(), (X509Certificate) certificate, SMIMESignedGenerator.DIGEST_SHA1, new AttributeTable(signedAttrs), null); 427 428 gen.addCertificatesAndCRLs(certsAndcrls); 429 430 //TODO: Extrair todos os headers de unsignedMessage 431 432 // Gera a assinatura 433 Object content = unsignedMessage.getContent(); 434 435 //TODO: igualar unsignedMessage a null 436 //TODO: Pegar os headers do objeto que guardarï¿œ esses headers quando necessï¿œrio. 437 438 MimeMultipart mimeMultipartContent = null; 439 PreencodedMimeBodyPart mimeBodyPartContent = null; 440 441 if (content.getClass().getName().contains("MimeMultipart")) { 442 mimeMultipartContent = (MimeMultipart) content; 443 } else { 444 String encoding = MimeUtility.getEncoding(unsignedMessage.getDataHandler()); 445 mimeBodyPartContent = new PreencodedMimeBodyPart(encoding); 446 if (encoding.equalsIgnoreCase("quoted-printable")) { 447 ByteArrayOutputStream os = new ByteArrayOutputStream(); 448 OutputStream encode = MimeUtility.encode(os, encoding); 449 OutputStreamWriter writer = new OutputStreamWriter(encode, "iso-8859-1"); 450 writer.write(content.toString()); 451 writer.flush(); 452 mimeBodyPartContent.setText(os.toString(), "iso-8859-1"); 453 os = null; 454 encode = null; 455 writer = null; 456 } else { 457 mimeBodyPartContent.setText(content.toString(), "iso-8859-1"); 458 } 459 mimeBodyPartContent.setHeader("Content-Type", unsignedMessage.getHeader("Content-Type", null)); 460 } 461 content = null; 462 463 // 464 // extract the multipart object from the SMIMESigned object. 465 // 466 MimeMultipart mm = null; 467 if (mimeMultipartContent == null) { 468 mm = gen.generate(mimeBodyPartContent, providerName); 469 mimeBodyPartContent = null; 470 } else { 471 MimeBodyPart multipartMsg = new MimeBodyPart(); 472 multipartMsg.setContent(mimeMultipartContent); 473 mm = gen.generate(multipartMsg, providerName); 474 multipartMsg = null; 475 mimeMultipartContent = null; 476 } 477 478 gen = null; 479 480 MimeMessage body = new MimeMessage(session); 481 body.setFrom(unsignedMessage.getFrom()[0]); 482 body.setRecipients(Message.RecipientType.TO, unsignedMessage.getRecipients(Message.RecipientType.TO)); 483 body.setRecipients(Message.RecipientType.CC, unsignedMessage.getRecipients(Message.RecipientType.CC)); 484 body.setRecipients(Message.RecipientType.BCC, unsignedMessage.getRecipients(Message.RecipientType.BCC)); 485 body.setSubject(unsignedMessage.getSubject(), "iso-8859-1"); 486 487 // Atrafuia o resto dos headers 488 body.setHeader("Return-Path", unsignedMessage.getHeader("Return-Path", null)); 489 body.setHeader("Message-ID", unsignedMessage.getHeader("Message-ID", null)); 490 body.setHeader("X-Priority", unsignedMessage.getHeader("X-Priority", null)); 491 body.setHeader("X-Mailer", unsignedMessage.getHeader("X-Mailer", null)); 492 body.setHeader("Disposition-Notification-To", unsignedMessage.getHeader("Disposition-Notification-To", null)); 493 body.setHeader("Date", unsignedMessage.getHeader("Date", null)); 494 body.setContent(mm, mm.getContentType()); 495 mm = null; 496 497 if (setup.getParameter("debug").equalsIgnoreCase("true")) { 498 System.out.println("\nHeaders do e-mail original:\n"); 499 } 500 501 body.saveChanges(); 502 503 ByteArrayOutputStream oStream = new ByteArrayOutputStream(); 504 505 oStream = new ByteArrayOutputStream(); 506 body.writeTo(oStream); 507 508 body = null; 509 return oStream.toString("iso-8859-1"); 510 511 } 512 513 /** 514 * Método utilizado para criptografar um e-mail 515 * @param source 516 * @return 517 */ 518 public String cipherMail(Map<String, String> data) throws IOException, GeneralSecurityException, MessagingException, CMSException, SMIMEException { 519 520 //Pega certificado do usuário. 521 522 Key privateKey = null; 523 if (this.keystoreStatus == DigitalCertificate.KEYSTORE_DETECTED) { 524 String pin = DialogBuilder.showPinDialog(this.parentFrame, this.setup); 525 if (pin != null) { 526 openKeyStore(pin.toCharArray()); 527 privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), pin.toCharArray()); 528 } else { 529 return null; 530 } 531 } /* 532 else if (this.keystoreStatus == DigitalCertificate.KEYSTORE_ALREADY_LOADED){ 533 if (DialogBuilder.showPinNotNeededDialog(this.parentFrame)){ 534 openKeyStore(null); 535 privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), null); 536 } 537 else { 538 return null; 539 } 540 } 541 */ else { 542 543 //DialogBuilder.showMessageDialog(this.parentFrame, "Nenhum token/smartcard foi detectado.\nOperação não pôde ser realizada!"); 544 DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate001"), this.setup); 545 return null; 546 } 547 548 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 549 550 X509Certificate cert = (X509Certificate) getCert(); 551 552 RecipientId recId = new RecipientId(); 553 recId.setSerialNumber(cert.getSerialNumber()); 554 recId.setIssuer(cert.getIssuerX500Principal()); 555 556 Properties props = System.getProperties(); 557 Session session = Session.getDefaultInstance(props, null); 558 559 String fullMsg = data.get("body"); 560 InputStream is = new ByteArrayInputStream(fullMsg.getBytes("iso-8859-1")); 561 MimeMessage encriptedMsg = new MimeMessage(session, is); 562 563 Provider prov = Security.getProvider(providerName); 564 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 565 System.out.println("Serviços do provider " + providerName + ":\n" + prov.getInfo()); 566 for (Provider.Service service : prov.getServices()) { 567 System.out.println(service.toString() + ": " + service.getAlgorithm()); 568 } 569 } 570 571 if (setup.getParameter("debug").equalsIgnoreCase("true")) { 572 System.out.println("Email criptografado:\n" + fullMsg); 573 } 574 575 SMIMEEnvelopedParser m = new SMIMEEnvelopedParser(encriptedMsg); 576 if (setup.getParameter("debug").equalsIgnoreCase("true")) { 577 System.out.println("Algoritmo de encriptação: " + m.getEncryptionAlgOID()); 578 } 579 580 AlgorithmParameters algParams = m.getEncryptionAlgorithmParameters("BC"); 581 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 582 System.out.println("Parâmetros do algoritmo: " + algParams.toString()); 583 } 584 585 RecipientInformationStore recipients = m.getRecipientInfos(); 586 RecipientInformation recipient = recipients.get(recId); 587 588 if (recipient != null) { 589 String retorno; 590 591 MimeBodyPart decriptedBodyPart = SMIMEUtil.toMimeBodyPart(recipient.getContent(privateKey, getProviderName())); 592 593 if ((new ContentType(decriptedBodyPart.getContentType())).getSubType().equalsIgnoreCase("x-pkcs7-mime")) { 594 StringBuffer sb = new StringBuffer(encriptedMsg.getSize()); 595 596 for (Enumeration e = encriptedMsg.getAllHeaderLines(); e.hasMoreElements();) { 597 String header = (String) e.nextElement(); 598 if (!header.contains("Content-Type") && 599 !header.contains("Content-Transfer-Encoding") && 600 !header.contains("Content-Disposition")) { 601 sb.append(header); 602 sb.append("\r\n"); 603 } 604 } 605 ByteArrayOutputStream oStream = new ByteArrayOutputStream(); 606 decriptedBodyPart.writeTo(oStream); 607 decriptedBodyPart = null; 608 encriptedMsg = null; 609 610 sb.append(oStream.toString("iso-8859-1")); 611 612 retorno = sb.toString(); 613 614 } else { 615 encriptedMsg.setContent(decriptedBodyPart.getContent(), decriptedBodyPart.getContentType()); 616 encriptedMsg.saveChanges(); 617 618 ByteArrayOutputStream oStream = new ByteArrayOutputStream(); 619 encriptedMsg.writeTo(oStream); 620 encriptedMsg = null; 621 622 retorno = oStream.toString("iso-8859-1"); 623 } 624 625 return retorno; 626 } else { 627 //DialogBuilder.showMessageDialog(this.parentFrame, "Não é possível ler este e-mail com o Certificado Digital apresentado!\n" + 628 // "Motivo: Este e-mail não foi cifrado com a chave pública deste Certificado Digital."); 629 DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate002"), this.setup); 630 return null; 631 } 632 } 633 634 /** 635 * Pega as credenciais de login do dono do certificado do serviço de verificação de certificados 636 * @param pin pin para acessar o token 637 * @return resposta Array de Strings em que: 638 * Indice 0: código de retorno; 639 * Indice 1: username se código de retorno for 0, senão mensagem de erro; 640 * Indice 2: senha decriptada se código de retorno for 0, senão não existe; 641 * @throws SSLHandshakeException 642 * @throws HttpException 643 * @throws IOException 644 * @throws GeneralSecurityException 645 */ 646 public String[] getCredentials(String pin) throws SSLHandshakeException, HttpException, IOException, GeneralSecurityException { 647 648 String[] resposta = null; 649 650 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 651 System.out.println("Proxy Configurado no browser: " + System.getProperty("http.proxyHost") + ":" + System.getProperty("http.proxyPort")); 652 } 653 654 // Registra novo protocolo https, utilizando nova implementação de AuthSSLProtocolSocketFactory 655 Protocol.registerProtocol("https", new Protocol("https", 656 (ProtocolSocketFactory) new AuthSSLProtocolSocketFactory(TRUST_STORES_URLS, TRUST_STORES_PASSWORDS, this.setup), 657 443)); 658 659 HttpClient httpclient = new HttpClient(); 660 // Define um método post para o link do serviço de verificação de certificados 661 if (System.getProperty("http.proxyHost") != null && System.getProperty("http.proxyPort") != null) { 662 httpclient.getHostConfiguration().setProxy(System.getProperty("http.proxyHost"), 663 Integer.parseInt(System.getProperty("http.proxyPort"))); 664 } 665 PostMethod httppost = new PostMethod("https://" + hostAddress + "/security/vercert.php"); 666 667 try { 668 // Adiciona parâmetro certificado no método post, executa o método, pega a resposta do servidor 669 // como uma string com CRLF de separador entre os campos e gera um array de Strings 670 httppost.addParameter("certificado", Base64Utils.der2pem(cert.getEncoded())); 671 httpclient.executeMethod(httppost); 672 resposta = httppost.getResponseBodyAsString().split(CRLF); 673 674 if (resposta.length > 2) { 675 if (Integer.parseInt(resposta[0].trim()) == 0) { 676 // Se código da resposta for zero, decripta a senha criptografada do usuário 677 resposta[2] = decriptPassword(resposta[2].trim(), pin); 678 } 679 } 680 681 } catch (IOException e) { 682 // Se for instância de SSLHandshakeException faz um cast para este tipo e lança a exceção novamente 683 // Isto é usado para diferenciar o tipo de falha, para que a mensagem para o usuário seja mostrada de 684 // acordo. 685 if (e instanceof SSLHandshakeException) { 686 throw (SSLHandshakeException) e; 687 } 688 // senão lança novamente a exceção do tipo IOException 689 throw e; 690 } finally { 691 // fecha a conexão 692 httppost.releaseConnection(); 693 } 694 695 return resposta; 696 } 697 698 /** 699 * Decripta a senha criptografada 700 * @param encodedPassword senha criptografada e codificada em base64 para ser decriptada 701 * @param pin pin para acessar a KeyStore 702 * @return decodedPassword 703 * @throws GeneralSecurityException se algum problema ocorrer na decriptação da senha. 704 */ 705 public String decriptPassword(String encodedPassword, String pin) throws GeneralSecurityException { 706 707 String decodedPassword = new String(); 708 709 // Pega a chave privada do primeiro certificado armazenado na KeyStore 710 Enumeration<String> en = this.keyStore.aliases(); 711 String certAlias = en.nextElement(); 712 Key privateKey = this.keyStore.getKey(certAlias, pin.toCharArray()); 713 714 // Inicializa os cipher com os parâmetros corretos para realizar a decriptação 715 Cipher dcipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 716 dcipher.init(Cipher.DECRYPT_MODE, privateKey); 717 718 // Decodifica a senha em base64 e a decripta 719 decodedPassword = new String(dcipher.doFinal(Base64Utils.base64Decode(encodedPassword))); 720 721 return decodedPassword.trim(); 722 723 } 724 725 /** 726 * Carrega um novo SecurityProvider 727 * @param pkcs11Config Linha de configuração do SmartCard ou Token 728 * @throws KeyStoreException Quando não conseguir iniciar a KeyStore, ou a lib do Token 729 * ou Smartcard não foi encontrada, ou o usuário não inseriu o Token. 730 */ 731 private void loadKeyStore() throws KeyStoreException { 732 733 //Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(pkcs11Config.getBytes())); 734 //Security.addProvider(pkcs11Provider); 735 this.keyStore = KeyStore.getInstance("PKCS11"); 736 this.providerName = keyStore.getProvider().getName(); 737 738 } 739 740 /** 741 * Abre a keystore passando o pin 742 * @param pin pin para acessar o Token 743 */ 744 public void openKeyStore(char[] pin) throws IOException { 745 746 try { 747 748 if (this.keyStore.getType().equals("PKCS11")) { 749 this.keyStore.load(null, pin); 750 } else { 751 this.keyStore.load(this.pkcs12Input, pin); 752 } 753 754 this.cert = this.keyStore.getCertificate(this.keyStore.aliases().nextElement()); 755 756 System.out.println("Aliases (" + this.keyStore.size() + "): "); 757 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 758 for (Enumeration alias = this.keyStore.aliases(); alias.hasMoreElements();) { 759 System.out.println(alias.nextElement()); 760 } 761 } 762 763 } catch (GeneralSecurityException e) { 764 if (this.setup.getParameter("debug").equalsIgnoreCase("true")) { 765 e.printStackTrace(); 766 } 767 } 768 769 } 770 771 /** 772 * @return the cert 773 */ 774 Certificate getCert() { 775 return this.cert; 776 } 777 778 /** 779 * @param cert the cert to set 780 */ 781 void setCert(Certificate cert) { 782 this.cert = cert; 783 } 727 784 }
Note: See TracChangeset
for help on using the changeset viewer.