Monday Apr 18, 2011

Time back to blog

In the past two years, a few new features are designed in JDK 7. I will try to demonstrate some of them in this blog, especially weak cryptographic algorithm control and TLS 1.1/1.2.

Monday Jul 13, 2009

An Aggregate of Feeds: Top Influencers on IT Security

An aggregate of feeds, http://feeds.feedburner.com/influenceronsec, from Bruce Schneier, Alan Shimel, and more.

Thursday Jul 02, 2009

Enable OCSP checking

If a certificate is issued with a authority information access extension which indicates the OCSP access method and location, one can enable the default implementation of OCSP checker during building or validating a certification path.

Maybe you need to check your certificate firstly, in the purpose of making sure it includes a OCSP authority information access extension:

#${JAVA_HOME}/bin/keytool -printcert -v -file target.cert

You are expected to see similar lines in the output:

#3: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[accessMethod: 1.3.6.1.5.5.7.48.1
accessLocation: URIName: http://onsite-ocsp.verisign.com]
]

In the above output, "http://onsite-ocsp.verisign.com" indicates the location of the OCSP service.

If you find one of similar authority information access extension in your certificate path, you need to enable OCSP checker.

For Sun PKIX implementation, OCSP checking is not enabled by default for compatibility, note that enabling OCSP checking only has an effect if revocation checking has also been enabled. So, in order to enable OCSP checker, first of all, you need to active certificate revocation checking; then active OCSP checking. It is simple and straightforward, only needs a few lines.

PKIXParameters params = new PKIXParameters(anchors);

// Activate certificate revocation checking
params.setRevocationEnabled(true);

// Activate OCSP
Security.setProperty("ocsp.enable", "true");

After that above two configurations, the default Sun PKIX implementation will try to get certificate status from the OCSP service indicated in the authority information access extension. For the above example, "http://onsite-ocsp.verisign.com" is the OCSP service. The enabled Sun OCSP checker will send certificate status request to the service, get response, and analysis the status from the response, if the status is revoked or unknown, the target certificate would be rejected.

Here is a sample code I wrote help you test your certificates and OCSP service, hope it helps.

/\*\*
 \* @author Xuelei Fan
 \*/
import java.io.\*;
import java.net.SocketException;
import java.util.\*;
import java.security.Security;
import java.security.cert.\*;

public class AuthorizedResponderNoCheck {

    static String selfSignedCertStr =
        "-----BEGIN CERTIFICATE-----\\n" +
        // copy your trust anchor certificate here, in PEM format.
        "-----END CERTIFICATE-----";

    static String trusedCertStr =
        "-----BEGIN CERTIFICATE-----\\n" +
        // copy your trusted enterprise certificate here, in PEM format.
        "-----END CERTIFICATE-----";

    static String issuerCertStr =
        "-----BEGIN CERTIFICATE-----\\n" +
        // copy the intermediate CA certificate here, in PEM format.
        "-----END CERTIFICATE-----";

    static String targetCertStr =
        "-----BEGIN CERTIFICATE-----\\n" +
        // copy the target certificate here, in PEM format.
        "-----END CERTIFICATE-----";


    private static CertPath generateCertificatePath()
            throws CertificateException {
        // generate certificate from cert strings
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        ByteArrayInputStream is =
            new ByteArrayInputStream(issuerCertStr.getBytes());
        Certificate issuerCert = cf.generateCertificate(is);

        is = new ByteArrayInputStream(targetCertStr.getBytes());
        Certificate targetCert = cf.generateCertificate(is);

        is = new ByteArrayInputStream(trusedCertStr.getBytes());
        Certificate trusedCert = cf.generateCertificate(is);

        is.close();

        // generate certification path
        List list = Arrays.asList(new Certificate[] {
                        targetCert, issuerCert, trusedCert});

        return cf.generateCertPath(list);
    }

    private static Set generateTrustAnchors()
            throws CertificateException {
        // generate certificate from cert string
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        ByteArrayInputStream is =
                    new ByteArrayInputStream(selfSignedCertStr.getBytes());
        Certificate selfSignedCert = cf.generateCertificate(is);

        is.close();

        // generate a trust anchor
        TrustAnchor anchor =
            new TrustAnchor((X509Certificate)selfSignedCert, null);

        return Collections.singleton(anchor);
    }

    public static void main(String args[]) throws Exception {

        // if you work behind proxy, configure the proxy.
        System.setProperty("http.proxyHost", "proxyhost");
        System.setProperty("http.proxyPort", "proxyport");

        CertPath path = generateCertificatePath();
        Set anchors = generateTrustAnchors();

        PKIXParameters params = new PKIXParameters(anchors);

        // Activate certificate revocation checking
        params.setRevocationEnabled(true);

        // Activate OCSP
        Security.setProperty("ocsp.enable", "true");

        // Activate CRLDP
        System.setProperty("com.sun.security.enableCRLDP", "true");

        // Ensure that the ocsp.responderURL property is not set.
        if (Security.getProperty("ocsp.responderURL") != null) {
            throw new
                Exception("The ocsp.responderURL property must not be set");
        }

        CertPathValidator validator = CertPathValidator.getInstance("PKIX");

        validator.validate(path, params);
    }
}

Thursday Jun 25, 2009

An Aggregate of Feeds on Java Security and Networking

To facilitate keeping track of blogs on java security and networking, I just created an aggregate of feeds, http://feeds.feedburner.com/javasec, and subscribed it to my feed reader, thunderbird. If you are blogging on Java security or networking, please let me know, I would like subscribe to your feed and add it into the aggregator

Of course, you are welcome to subscribe to the aggregated feed, http://feeds.feedburner.com/javasec.

Tuesday Jun 16, 2009

JSSE Troubleshooting: Certificates Order in TLS Handshaking

Issue:

Failed with a exception: java.security.cert.CertPathValidatorException: subject/issuer name chaining check failed.

Example:

Test case:
     1  //
     2  // JSSE Troubleshooting: Disordered Certificate List in TLS Handshaking
     3  //
     4  import java.net.\*;
     5
     6  public class DisorderedCertificateList {
     7      public static void main(String[] Arguments) throws Exception {
     8          URL url = new URL("https://myservice.example.com/");
     9          URLConnection connection = url.openConnection();
    10
    11          connection.getInputStream().close();
    12      }
    13  }
	
Test environment:

The HTTPS server, myservice.example.com, is configurated with a certificate path that the certificates in the path is out of order. For example, the expected certificate path is server_certificate -> intermediate ca -> seld-signed root ca. However, the certificate path is configurated as server_certificate -> seld-signed root ca -> intermediate ca.

Test Result:
	Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: subject/issuer name chaining check failed
		at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
		at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1627)
		at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:204)
		at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:198)
		at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:994)
		at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:142)
		at sun.security.ssl.Handshaker.processLoop(Handshaker.java:533)
		at sun.security.ssl.Handshaker.process_record(Handshaker.java:471)
		at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:904)
		at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1132)
		at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1159)
		at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1143)
		at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:423)
		at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
		at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:997)
		at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
		at DisorderedCertificateList.main(DisorderedCertificateList.java:11)
	Caused by: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: subject/issuer name chaining check failed
		at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:266)
		at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:249)
		at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:172)
		at sun.security.validator.Validator.validate(Validator.java:235)
		at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
		at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
		at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
		at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:973)
		... 12 more
	Caused by: java.security.cert.CertPathValidatorException: subject/issuer name chaining check failed
		at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:153)
		at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:321)
		at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:186)
		at java.security.cert.CertPathValidator.validate(CertPathValidator.java:267)
		at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:261)
		... 19 more
	

Cause:

Per the TLS specification (page 39, section 7.4.2, RFC2246), the certificate list passed to server Certificate message or client Certificate message "is a sequence (chain) of X.509v3 certificates. The sender's certificate must come first in the list. Each following certificate must directly certify the one preceding it."

So, the certificate order of the above test case, server_certificate -> seld-signed root ca -> intermediate ca, is not a TLS specification compliant behavior, the TLS handshaking is expected to fail.

Solution:

Checking the TLS/SSL configuration, and make sure that the certificate list sent to peer is properly configuated and in order.


Linkage to the blog entry at simabc.blogspot.com

Saturday May 23, 2009

FIPS 140 Compliant Mode for SunJSSE

In the Java™ 6 Security Enhancements, it says that "The SunJSSE provider now supports an experimental FIPS 140 compliant mode.  When enabled and used in combination with the SunPKCS11 provider and an appropriate FIPS 140 certified PKCS#11 token, SunJSSE is FIPS 140 compliant."  Except that, we cannot find any more document on how to enable FIPS mode and how the FIPS mode works with SunJSSE. Normally, developers could a few hints from Andreas blog,. The Java PKCS#11 Provider and NSS, althought it is far from enough to understand the FIPS mode of SunJSSE. The following is a unpublished document, hope it helps.

 

FIPS 140 Compliant Mode for SunJSSE

In Sun's Java SE implementation version 6 or later, the SunJSSE provider, which contains the SSL/TLS implementation, can be configured to operate in a FIPS 140 compliant mode instead of its default mode. This document describes the FIPS 140 compliant mode (subsequently called "FIPS mode").

Configuring SunJSSE for FIPS Mode

SunJSSE is configured in FIPS mode by associating it with an appropriate FIPS 140 certified cryptographic provider that supplies the implementations for all cryptographic algorithms required by SunJSSE. This can be done in one of the following ways:

  1. edit the file ${java.home}/lib/security/java.security and modify the line that lists com.sun.net.ssl.internal.ssl.Provider to list the provider name of the FIPS 140 certified cryptographic provider. For example if the name of the cryptographic provider is SunPKCS11-NSS, change the line from

      security.provider.4=com.sun.net.ssl.internal.ssl.Provider

    to

      security.provider.4=com.sun.net.ssl.internal.ssl.Provider SunPKCS11-NSS

    The class for the provider of the given name must also be listed as a security provider in the java.security file.

  2. at runtime, call the constructor of the SunJSSE provider that takes a java.security.Provider object as a parameter. For example, if the variable cryptoProvider is a reference to the cryptographic provider, call new com.sun.net.ssl.internal.ssl.Provider(cryptoProvider).

  3. at runtime, call the constructor of the SunJSSE provider that takes a String object as a parameter. For example if the cryptographic provider is called SunPKCS11-NSS call new com.sun.net.ssl.internal.ssl.Provider("SunPKCS11-NSS"). A provider with the specified name must be one of the configured security providers.

Within a given Java process, SunJSSE can be used either in FIPS mode or in default mode, but not both at the same time. Once SunJSSE has been initialized, it is not possible to change the mode. This means that if one of the runtime configuration options is used (option 2 or 3), the configuration must take place before any SSL/TLS operation.

Note that only the specified configured provider will be used by the SunJSSE for any and all cryptographic operations. All other cryptographic providers including those included with the Java SE implementation will be ignored and not used.

Difference Between FIPS Mode and Default Mode

In FIPS mode, SunJSSE behaves in a way identical to default mode, except for the following differences.

In FIPS mode:

  • SunJSSE will perform all cryptographic operations using the cryptographic provider that was configured as described above. This includes symmetric and asymmetric encryption, signature generation and verification, message digests and message authentication codes, key generation and key derivation, random number generation, etc.

  • If the configured cryptographic provider reports any error by throwing an exception, SunJSSE will abort the current operation and propagate the exception to the application.

  • If the configured cryptographic provider believes it had a critical error such as a self test failure per FIPS guidelines, it needs to remain in an error state until it is re-initialized. The application using the SunJSSE configured with the FIPS cryptographic module will have to be restarted. This ensures that the FIPS module will not allow critical errors to compromise security.

  • Only TLS 1.0 and later can be used. SSL 2.0 and SSL 3.0 are not available. Any attempt to enable SSL 2.0 or 3.0 will fail with an exception.

  • The list of ciphersuites is limited to those that utilize appropriate algorithms. The current list of possible ciphersuites is given below. Any attempt to enable a ciphersuite not on the list will fail with an exception.

Ciphersuites Usable in FIPS Mode

The following is the current list of ciphersuites which can be used by SunJSSE in FIPS mode with their names and the id as assigned in the TLS protocol provided that the configured cryptographic FIPS module supports the necessary algorithms. Note that although SunJSSE uses the prefix SSL_ in the name of some of these ciphersuites, this is for compatibility with earlier versions of the specification only. In FIPS mode, SunJSSE will always use TLS 1.0 or later and implement the ciphersuites as required by those specifications.

SSL_RSA_WITH_3DES_EDE_CBC_SHA

0x000a

SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA

0x0016

TLS_RSA_WITH_AES_128_CBC_SHA

0x002f

TLS_DHE_DSS_WITH_AES_128_CBC_SHA

0x0032

TLS_DHE_RSA_WITH_AES_128_CBC_SHA

0x0033

TLS_RSA_WITH_AES_256_CBC_SHA

0x0035

TLS_DHE_DSS_WITH_AES_256_CBC_SHA

0x0038

TLS_DHE_RSA_WITH_AES_256_CBC_SHA

0x0039

TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA

0xC003

TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA

0xC004

TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA

0xC005

TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA

0xC008

TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA

0xC009

TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA

0xC00A

TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA

0xC00D

TLS_ECDH_RSA_WITH_AES_128_CBC_SHA

0xC00E

TLS_ECDH_RSA_WITH_AES_256_CBC_SHA

0xC00F

TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA

0xC012

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

0xC013

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

0xC014

TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA

0xC017

TLS_ECDH_anon_WITH_AES_128_CBC_SHA

0xC018

TLS_ECDH_anon_WITH_AES_256_CBC_SHA

0xC019

Conclusion

When SunJSSE is configured in FIPS 140 compliant mode together with an appropriate FIPS 140 certified cryptographic provider, for example Network Security Services (NSS) in its FIPS mode, SunJSSE is FIPS 140 compliant. 

 

Wednesday May 13, 2009

Please remove the unsafe dependence on Permission.toString()

Recently, we made a correction on the implement of java.security.Permission.toString(). The specification says, "Returns a string describing this Permission. The convention is to specify the class name, the permission name, and the actions in the following format: '("ClassName" "name" "actions")'."[1] That is, the specification requires all components, ClassName, name, and actions, to be enclosed in double quotes, but JDK implementation of this method ignores this requirement, which returns string without double quotes. It seems that double quotes make sense, to differentiate between permissions of the same class with name "permit to write" and empty actions and another permission with name "permit to" and actions "write". A bug reported agasint the issue[2], and the bug was fixed recently[3].

But shortly after, I received many queries that the update break some test cases. In those test cases, the Permission.toString() is used to check against a hard coded string, which is expected no double qotes, for example,

    try {
    } catch (AccessControlException ace) {
        if (ace.getPermission().toString().indexOf("FilePermission filename read") < 0) {
            // run the codes that the exception is not a FilePermission/filename/read.
        } else {
            // run the codes that the exception is a FilePermission/filename/read.
        }
    }

The above codes' behaviors will diff with the bug fix[3], because now the the Permission.toString is expected as '"FilePermission" "filename" "read"', instead of 'FilePermission filename read".

For those application that depends on the Permission.toString() like above, I would suggest update those codes with Permission.getClass().getName(), Permissin.getName(), and Permission.getActions() accordingly. The above codes would look like:

    try {
    } catch (AccessControlException ace) {
        Permission perm = ace.getPermission();
        if (perm.getClass().getName().equals("FilePermission") && perm.getName().equals("filename") && perm.getActions("read")) {
            // run the codes that the exception is not a FilePermission/filename/read.
        } else {
            // run the codes that the exception is a FilePermission/filename/read.
        }
    }

The above code is much safer the using the Permission.toString(). For the issue, I only get reports on test cases, no reports to me on practical appliaction by now. But in case your application have similar usage as the above hard coded example, please DO remove the dependence for your application on JDK 7.

[1]: http://java.sun.com/javase/6/docs/api/java/security/Permission.html#toString()
[2]: http://bugs.sun.com/view_bug.do?bug_id=6549506
[3]: http://hg.openjdk.java.net/jdk7/tl/jdk/rev/b656e842e1be

 

Friday Nov 10, 2006

Fine granularity diagnosis on security

You're supposed  to familiar with the java.security.debug property, otherwise please refer to the sample chapter of "Java Security".

Before Java 6, if the security debug property, java.security.debug, is enabled, a large volume of debug output will be dumped. For example, if  java.security.debug deinfed as access:stack, every stack will be dumped if a permission is checked on. Even for a simple application, the output normally runs over several pages. In server products, such as Sun Web Server and App Server, the amount of output is overwhelming, analysis them manually  is a nightmare. So customers often give up in frustration while trying to follow it to diagnose problems.

Things get changed at Java 6, the java security packages introduced two new java.security.debug options, permission and codebase. Let's have a look at the help message of security debugger.

    $ java -Djava.security.debug=help Foo

    all           turn on all debugging
    access        print all checkPermission results
    combiner      SubjectDomainCombiner debugging
    gssloginconfig
                  GSS LoginConfigImpl debugging
    jar           jar verification
    logincontext  login context results
    policy        loading and granting
    provider      security provider debugging
    scl           permissions SecureClassLoader assigns

    The following can be used with access:

    stack         include stack trace
    domain        dump all domains in context
    failure       before throwing exception, dump stack
                  and domain that didn't have permission

    The following can be used with stack and domain:

    permission.<classname>
                  only dump output if specified permission
                  is being checked
    codebase.<URL>
                  only dump output if specified codebase
                  is being checked

    Note: Separate multiple options with a comma
    

 Note that there's a bug on the help message that "permission.<classname>" should be "permission=<classname>", and "codebase.<URL>" should be "codebase=<URL>". And in the two options, spaces are not allowed before and after the sign "=".

Let's show the two options with a sample class, Foo.

// Sample class to illustrate debug options import java.io.FileInputStream; import java.io.ObjectInputStream; public class Foo { public static void main(String[] args) throws Exception { ObjectInputStream ois = null; try { FileInputStream fis = new FileInputStream("./foo.obj"); ois = new ObjectInputStream(fis); Object dummy = ois.readObject(); } finally { if (ois != null) { ois.close(); } } } }


permission=<classname>:

permission=<classname> option is used with stack trace or domain option, when a certain classname is specified, the security debugger will only dump the stacks or the domain that checking the specified permission. Here, classname is the canonical class name of the specified permission, and the classname is case sensitive.

The option is particularly useful for customers who have their own permissions to take care of, or only care to follow the evaluation details of some certain permissions.

 For the above sample class, the Java security will check the following permissions on Foo.main():

  1. java.io.FilePermission (1 time)
  2. java.lang.RuntimePermission (1 time)
  3. java.lang.reflect.ReflectPermission (5 times)

Sometimes, users maybe only want to trace the stacks that checking java.io.FilePermission, or really do not want to care java.lang.reflect.ReflectPermission. Try to run the example and see what happened.

$ java -Djava.security.manager \\
  -Djava.security.debug=access,stack Foo

(The output omitted)

$ java -Djava.security.manager \\
  -Djava.security.debug=access,stack,permission=java.io.FilePermission Foo

java.lang.Exception: Stack trace
        at java.lang.Thread.dumpStack(Thread.java:1206)
        at java.security.AccessController.checkPermission(AccessController.java:532)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
        at java.lang.SecurityManager.checkRead(SecurityManager.java:871)
        at java.io.File.isDirectory(File.java:752)
        at sun.net.www.ParseUtil.fileToEncodedURL(ParseUtil.java:242)
        at sun.security.provider.PolicyFile.canonicalizeCodebase(PolicyFile.java:1806)
        at sun.security.provider.PolicyFile.access$700(PolicyFile.java:263)
        at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1220)
        at sun.security.provider.PolicyFile$5.run(PolicyFile.java:1218)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1217)
        at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1165)
        at sun.security.provider.PolicyFile.implies(PolicyFile.java:1120)
        at java.security.ProtectionDomain.implies(ProtectionDomain.java:213)
        at java.security.AccessControlContext.checkPermission(AccessControlContext.java:301)
        at java.security.AccessController.checkPermission(AccessController.java:546)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
        at java.lang.SecurityManager.checkRead(SecurityManager.java:871)
        at java.io.FileInputStream.<init>(FileInputStream.java:100)
        at java.io.FileInputStream.<init>(FileInputStream.java:66)
        at Foo.main(Foo.java:11)
access: access allowed (java.io.FilePermission /some/somedir read)

$ java -Djava.security.manager \\
  -Djava.security.debug="access,stack,permission=java.io.FilePermission \\
  permission=java.lang.RuntimePermission" Foo

(The output omitted)

codebase=<URL>:

codebase=<URL> option is used with stack trace or domain option, when a certain codebase is specified, the security debugger will only dump the stacks or the protection domain that from the specified code source defined by the codebase. Here, URL is the location of the specified code base. Note that because the comma (',") is used as multi options separator, if the URL contains comma, the security debugger would not work properly as expected, it is recommended that the URL should not include character comma (','), semicolon (';'), and  space.

This option would be useful when customer desires to trace the permissions impact of only the code in a given code souce, such as jar file.

About

A blog on security and networking

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today