Sahi with TLS1.1 - automation

Sahi OS V5.0 throws a Handshake failure exception after the application server being upgraded to TLS1.1. Using the sahi driver, I'm not able to navigate to any url's of this upgraded server. But the older one works fine.
Does anyone know how to configure this?
Here is the stacktrace:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
at net.sf.sahi.RemoteRequestProcessor.processHttp(RemoteRequestProcessor.java:151)........

I'm currently not sure how Sahi OS 5 does it, but we changed the SSL implementation in the code and changed the parameters in the browser.xml to prevent phantomjs from using SSLv3
Have a look at https://github.com/headissue/Sahi/commit/84c45f99f920893a7dfd39e2565819afd91c858e for reference and have a look at your browsers, if they still use SSLv3
Regards
globalworming

Two things fixed this issue:
Passing an argument to JVM to set the version of TLS to be used.
-Dhttps.protocols=TLSv1,TLSv1.1
Using the Java of same version in both client and server.

Related

Disabling Bouncy Castle

The application is currently running in java version build 1.7.0_79-b15 and the third party application upgraded its TLS to 1.3 version. We can't easily upgrade java version that will support TLS 1.3 and so we decided to use Bouncy Castle in order for us comply with the third party. We were able to connect to the third party system after using Bouncy Castle but, the existing mail service that is working on previous default java security is no longer working due to the error below.
Caused by: javax.mail.MessagingException: IOException while sending message;
nested exception is:
org.bouncycastle.tls.TlsFatalAlert: certificate_unknown(46)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:625)
at javax.mail.Transport.send0(Transport.java:169)
at javax.mail.Transport.send(Transport.java:98)
at org.apache.commons.mail.Email.sendMimeMessage(Email.java:1232)
... 72 more
Caused by: org.bouncycastle.tls.TlsFatalAlert: certificate_unknown(46)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.checkServerTrusted(Unknown Source)
at org.bouncycastle.jsse.provider.ProvTlsClient$1.notifyServerCertificate(Unknown Source)
at org.bouncycastle.tls.TlsUtils.processServerCertificate(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.handleServerCertificate(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
at org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1301)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at java.net.URL.openStream(URL.java:1037)
at javax.activation.URLDataSource.getInputStream(URLDataSource.java:107)
at javax.activation.DataHandler.writeTo(DataHandler.java:304)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1350)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:845)
at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:361)
at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:85)
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:883)
at javax.activation.DataHandler.writeTo(DataHandler.java:316)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1350)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:845)
at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:361)
at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:85)
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:883)
at javax.activation.DataHandler.writeTo(DataHandler.java:316)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1350)
at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1683)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:585)
... 75 more
Caused by: java.security.cert.CertificateException: Unable to find certificate chain.
at org.bouncycastle.jsse.provider.ProvX509TrustManager.validateChain(Unknown Source)
at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkTrusted(Unknown Source)
at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkServerTrusted(Unknown Source)
Are there any way to disable Bouncy Castle or processing certificate when sending message through SMTP? Or any way to fix it?
Any suggestions or help are highly appreciated. thanks!

"Algorithm ECDH not available" using bcprov & bctls on JRockit 6

I'm trying to authorize an old JBoss 5 running on JRockit 6 to access to a CAS server using a Let's encrypt certificate.
The problem is that Let's encrypt is not supported on JDK6 so I added the root certificate to the cacerts file.
Now the problem is that JDK 6 does not understand such big key (java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)) so I tried to switch to Bouncy Castle JCE/JCA by adding bcprov-jdk15on-1.61.jar & bctls-jdk15on-1.61.jar to the $JAVA_HOME/jre/lib/ext folder & added org.bouncycastle.jce.provider.BouncyCastleProvider & org.bouncycastle.jsse.provider.BouncyCastleJsseProvider as first security providers in $JAVA_HOME/jre/lib/security/java.security file as explained partly here.
After a java.lang.ArrayIndexOutOfBoundsException: 64 I switched from SunX509 to X.509 value for ssl.KeyManagerFactory.algorithm key in java.security file.
Now I have the following error (I think the same as this thread on Oracle forum):
java.security.NoSuchAlgorithmException: Algorithm ECDH not available
javax.crypto.KeyAgreement.getInstance(DashoA13*..)
org.bouncycastle.jcajce.util.DefaultJcaJceHelper.createKeyAgreement(Unknown Source)
org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.calculateKeyAgreement(Unknown Source)
org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDomain.calculateECDHAgreement(Unknown Source)
org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDH.calculateSecret(Unknown Source)
org.bouncycastle.tls.TlsECDHEKeyExchange.generatePreMasterSecret(Unknown Source)
org.bouncycastle.tls.TlsProtocol.establishMasterSecret(Unknown Source)
org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:167)
sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
org.jasig.cas.client.validation.Saml11TicketValidator.retrieveResponseFromServer(Saml11TicketValidator.java:216)
But by looking at org.bouncycastle.jcajce.provider.asymmetric.EC's sources such KeyAgreement should be correctly set by org.bouncycastle.jce.provider.BouncyCastleProvider.
But effectively, as it is the org.bouncycastle.jsse.provider.BouncyCastleJsseProvider which is used when creating a https client, this provider doesn't register this algorithm and I don't know how to do this.
Someone knows how to workaround this?
I have also tried to declare those jars as dependencies to my war and explicitely instanciate them like this:
static {
org.bouncycastle.jce.provider.BouncyCastleProvider bcp = new org.bouncycastle.jce.provider.BouncyCastleProvider();
java.security.Security.insertProviderAt(bcp, 1);
org.bouncycastle.jsse.provider.BouncyCastleJsseProvider bcjp = new org.bouncycastle.jsse.provider.BouncyCastleJsseProvider(bcp);
java.security.Security.insertProviderAt(bcjp, 1);
}
But then, I have this stack that seems to be linked to a problem in JBoss:
java.lang.SecurityException: JCE cannot authenticate the provider BC
javax.crypto.Cipher.getInstance(DashoA13*..)
org.bouncycastle.jcajce.util.ProviderJcaJceHelper.createCipher(Unknown Source)
org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.hasEncryptionAlgorithm(Unknown Source)
org.bouncycastle.tls.TlsUtils.isSupportedCipherSuite(Unknown Source)
org.bouncycastle.tls.TlsUtils.getSupportedCipherSuites(Unknown Source)
org.bouncycastle.jsse.provider.ProvTlsClient.getSupportedCipherSuites(Unknown Source)
org.bouncycastle.tls.AbstractTlsClient.init(Unknown Source)
org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:167)
sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
org.jasig.cas.client.validation.Saml11TicketValidator.retrieveResponseFromServer(Saml11TicketValidator.java:216)
Caused by: java.util.jar.JarException: Cannot parse jar:file:/opt/jboss-5.1.0.GA/server/default/deploy/myapp.war/WEB-INF/lib/bcprov-jdk15on-1.61.jar!/
javax.crypto.SunJCE_c.a(DashoA13*..)
javax.crypto.SunJCE_b.b(DashoA13*..)
javax.crypto.SunJCE_b.a(DashoA13*..)
javax.crypto.Cipher.getInstance(DashoA13*..)
org.bouncycastle.jcajce.util.ProviderJcaJceHelper.createCipher(Unknown Source)
org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.hasEncryptionAlgorithm(Unknown Source)
org.bouncycastle.tls.TlsUtils.isSupportedCipherSuite(Unknown Source)
org.bouncycastle.tls.TlsUtils.getSupportedCipherSuites(Unknown Source)
org.bouncycastle.jsse.provider.ProvTlsClient.getSupportedCipherSuites(Unknown Source)
org.bouncycastle.tls.AbstractTlsClient.init(Unknown Source)
org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:167)
sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
org.jasig.cas.client.validation.Saml11TicketValidator.retrieveResponseFromServer(Saml11TicketValidator.java:216)
In case, I have opened the issue #514 on BouncyCastle GitHub.
What you are seeing is consistent with the BouncyCastle JCE Provider not being registered. Hence the search for the ECDH Agreement is not finding it in the JCE search path.
To register the Provider dynamically simply add the following lines to your code
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleJsseProvider());
as per the BouncyCastle Specifications section 6.1 and the test sample code BouncyCastle JSSE Test Code
I suspect that you are not correctly initiating the environment
This problem was solved in https://github.com/bcgit/bc-java/issues/514 by anthony-o as it was caused by a re-packaging issue.
However, that solution did not work for me as my bouncycastle jars are not repackaged into shade/fat jars
Here is how I solved the issue: https://stackoverflow.com/a/59845413/497378
(I am not sure of the etiquette of posting link to answers from another stackoverflow question so please delete if not appropriate)
java.lang.SecurityException: JCE cannot authenticate the provider BC
I get the same error (and the JAR was directly from Maven, no repackaging was in place), I think because starting in BC 1.61 release JARs are signed using a more recent signature algorithm (or root certificate) that Java 6 is unable to verify.
By downgrading BC to 1.60 I managed to connect to a SNI-enabled TLS server (which wasn't reachable usually by Java 6). I used the following Maven dependency:
<dependency groupId="org.bouncycastle" artifactId="bctls-jdk15on" version="1.60"/>

Jmeter 3.1- javax.net.ssl.SSLException: Received fatal alert: protocol_version

We are trying to run https request in Jmeter 3.1.
But while executing getting following error.
javax.net.ssl.SSLException: Received fatal alert: protocol_version
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.writeRecord(Unknown Source)
at sun.security.ssl.AppOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at org.apache.jmeter.protocol.http.sampler.HTTPHC3Impl.sample(HTTPHC3Impl.java:269)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:74)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1166)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1155)
at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:475)
at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:418)
at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:249)
at java.lang.Thread.run(Unknown Source)
We tried following solutions but did't solved the issue:
added "https.default.protocol=TLSv1" in "jmeter.properties" file
Tried solution provided in
http://rajanmanoj.blogspot.in/2011/02/how-to-test-ssl-using-jmeter.html
this link
We are Using Jmeter 3.1, Java Jdk 1.7, Windows 7
Https default protocol may vary depending on the version of JVM.
You can change it. Go to jmeter home directory. Open jmeter.properties file. Uncomment line:
https.default.protocol=SSLv3
May be you need to restart jmeter after change. Not sure about that.
This is highly due to protocol version mismatch. There is mismatch between SSL protocol version used by the client and the server.
Make sure that you have latest version of Java and JMeter installed in your system. Also check for the security certificate in JMETER_HOME\bin folder.
You can check this question for more details.

Jenkins - ssh connection exception

This question may be asked multiple times but I need latest update on this issue.
I am trying to configure a slave for my jenkins Master but getting following exception:
ERROR: Unexpected error in launching a slave. This is probably a bug in Jenkins.
java.lang.IllegalStateException: Connection is not established!
at com.trilead.ssh2.Connection.getRemainingAuthMethods(Connection.java:1030)
at com.cloudbees.jenkins.plugins.sshcredentials.impl.TrileadSSHPasswordAuthenticator.canAuthenticate(TrileadSSHPasswordAuthenticator.java:82)
at com.cloudbees.jenkins.plugins.sshcredentials.SSHAuthenticator.newInstance(SSHAuthenticator.java:207)
at com.cloudbees.jenkins.plugins.sshcredentials.SSHAuthenticator.newInstance(SSHAuthenticator.java:169)
at hudson.plugins.sshslaves.SSHLauncher.openConnection(SSHLauncher.java:1173)
at hudson.plugins.sshslaves.SSHLauncher$2.call(SSHLauncher.java:701)
at hudson.plugins.sshslaves.SSHLauncher$2.call(SSHLauncher.java:696)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
[01/07/15 16:51:10] Launch failed - cleaning up connection
[01/07/15 16:51:10] [SSH] Connection closed.
Any idea of what's the issue here?

WSDL2Java certificate error

Using the WSDL2Java.bat included in Apache Axis2 to generate .java files from an online SOAP WSDL service, however I get an error about some certificate. I have no idea where this is coming from, it should work according to the instructions I was given.
Using AXIS2_HOME: C:\Users\****\Downloads\axis2-1.6.2-bin\axis2-1.6.2
Using JAVA_HOME: C:\Program Files\Java\jre7
Exception in thread "main" org.apache.axis2.wsdl.codegen.CodeGenerationException
: Error parsing WSDL
at org.apache.axis2.wsdl.codegen.CodeGenerationEngine.<init>(CodeGenerat
ionEngine.java:181)
at org.apache.axis2.wsdl.WSDL2Code.main(WSDL2Code.java:35)
at org.apache.axis2.wsdl.WSDL2Java.main(WSDL2Java.java:24)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.Validator
Exception: PKIX path building failed: sun.security.provider.certpath.SunCertPath
BuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source
)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect
(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown So
urce)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unk
nown Source)
at org.apache.axis2.wsdl.codegen.CodeGenerationEngine.<init>(CodeGenerat
ionEngine.java:99)
... 2 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find vali
d certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Sour
ce)
... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown
Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 22 more
Anyone got any hint on what the issue could be or where I should start looking?
Thanks
It seems you are trying to generate Java classes using a WSDL from an HTTPS URL. It fails when it is trying to validate the certificate.
Try to access the WSDL from your browser and it should give you a warning.
You can save the WSDL to your local directory and try to run WSDL2Java for that file.
However you might get similar errors when you access the web service via stub, if the endpoint is also an HTTPS URL.