提交 81eccafb 编写于 作者: M mullan

Merge

/* /*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -48,7 +48,7 @@ import sun.security.util.Cache; ...@@ -48,7 +48,7 @@ import sun.security.util.Cache;
*/ */
final class KeyCache { final class KeyCache {
private final Cache strongCache; private final Cache<IdentityWrapper, P11Key> strongCache;
private WeakReference<Map<Key,P11Key>> cacheReference; private WeakReference<Map<Key,P11Key>> cacheReference;
...@@ -77,7 +77,7 @@ final class KeyCache { ...@@ -77,7 +77,7 @@ final class KeyCache {
} }
synchronized P11Key get(Key key) { synchronized P11Key get(Key key) {
P11Key p11Key = (P11Key)strongCache.get(new IdentityWrapper(key)); P11Key p11Key = strongCache.get(new IdentityWrapper(key));
if (p11Key != null) { if (p11Key != null) {
return p11Key; return p11Key;
} }
...@@ -94,8 +94,8 @@ final class KeyCache { ...@@ -94,8 +94,8 @@ final class KeyCache {
Map<Key,P11Key> map = Map<Key,P11Key> map =
(cacheReference == null) ? null : cacheReference.get(); (cacheReference == null) ? null : cacheReference.get();
if (map == null) { if (map == null) {
map = new IdentityHashMap<Key,P11Key>(); map = new IdentityHashMap<>();
cacheReference = new WeakReference<Map<Key,P11Key>>(map); cacheReference = new WeakReference<>(map);
} }
map.put(key, p11Key); map.put(key, p11Key);
} }
......
...@@ -64,8 +64,10 @@ public class X509Factory extends CertificateFactorySpi { ...@@ -64,8 +64,10 @@ public class X509Factory extends CertificateFactorySpi {
private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX
private static final Cache certCache = Cache.newSoftMemoryCache(750); private static final Cache<Object, X509CertImpl> certCache
private static final Cache crlCache = Cache.newSoftMemoryCache(750); = Cache.newSoftMemoryCache(750);
private static final Cache<Object, X509CRLImpl> crlCache
= Cache.newSoftMemoryCache(750);
/** /**
* Generates an X.509 certificate object and initializes it with * Generates an X.509 certificate object and initializes it with
...@@ -90,7 +92,7 @@ public class X509Factory extends CertificateFactorySpi { ...@@ -90,7 +92,7 @@ public class X509Factory extends CertificateFactorySpi {
try { try {
byte[] encoding = readOneBlock(is); byte[] encoding = readOneBlock(is);
if (encoding != null) { if (encoding != null) {
X509CertImpl cert = (X509CertImpl)getFromCache(certCache, encoding); X509CertImpl cert = getFromCache(certCache, encoding);
if (cert != null) { if (cert != null) {
return cert; return cert;
} }
...@@ -151,7 +153,7 @@ public class X509Factory extends CertificateFactorySpi { ...@@ -151,7 +153,7 @@ public class X509Factory extends CertificateFactorySpi {
} else { } else {
encoding = c.getEncoded(); encoding = c.getEncoded();
} }
X509CertImpl newC = (X509CertImpl)getFromCache(certCache, encoding); X509CertImpl newC = getFromCache(certCache, encoding);
if (newC != null) { if (newC != null) {
return newC; return newC;
} }
...@@ -181,7 +183,7 @@ public class X509Factory extends CertificateFactorySpi { ...@@ -181,7 +183,7 @@ public class X509Factory extends CertificateFactorySpi {
} else { } else {
encoding = c.getEncoded(); encoding = c.getEncoded();
} }
X509CRLImpl newC = (X509CRLImpl)getFromCache(crlCache, encoding); X509CRLImpl newC = getFromCache(crlCache, encoding);
if (newC != null) { if (newC != null) {
return newC; return newC;
} }
...@@ -198,18 +200,17 @@ public class X509Factory extends CertificateFactorySpi { ...@@ -198,18 +200,17 @@ public class X509Factory extends CertificateFactorySpi {
/** /**
* Get the X509CertImpl or X509CRLImpl from the cache. * Get the X509CertImpl or X509CRLImpl from the cache.
*/ */
private static synchronized Object getFromCache(Cache cache, private static synchronized <K,V> V getFromCache(Cache<K,V> cache,
byte[] encoding) { byte[] encoding) {
Object key = new Cache.EqualByteArray(encoding); Object key = new Cache.EqualByteArray(encoding);
Object value = cache.get(key); return cache.get(key);
return value;
} }
/** /**
* Add the X509CertImpl or X509CRLImpl to the cache. * Add the X509CertImpl or X509CRLImpl to the cache.
*/ */
private static synchronized void addToCache(Cache cache, byte[] encoding, private static synchronized <V> void addToCache(Cache<Object, V> cache,
Object value) { byte[] encoding, V value) {
if (encoding.length > ENC_MAX_LENGTH) { if (encoding.length > ENC_MAX_LENGTH) {
return; return;
} }
...@@ -361,7 +362,7 @@ public class X509Factory extends CertificateFactorySpi { ...@@ -361,7 +362,7 @@ public class X509Factory extends CertificateFactorySpi {
try { try {
byte[] encoding = readOneBlock(is); byte[] encoding = readOneBlock(is);
if (encoding != null) { if (encoding != null) {
X509CRLImpl crl = (X509CRLImpl)getFromCache(crlCache, encoding); X509CRLImpl crl = getFromCache(crlCache, encoding);
if (crl != null) { if (crl != null) {
return crl; return crl;
} }
......
...@@ -59,12 +59,13 @@ public abstract class CertStoreHelper { ...@@ -59,12 +59,13 @@ public abstract class CertStoreHelper {
"SSLServer", "SSLServer",
"sun.security.provider.certpath.ssl.SSLServerCertStoreHelper"); "sun.security.provider.certpath.ssl.SSLServerCertStoreHelper");
}; };
private static Cache cache = Cache.newSoftMemoryCache(NUM_TYPES); private static Cache<String, CertStoreHelper> cache
= Cache.newSoftMemoryCache(NUM_TYPES);
public static CertStoreHelper getInstance(final String type) public static CertStoreHelper getInstance(final String type)
throws NoSuchAlgorithmException throws NoSuchAlgorithmException
{ {
CertStoreHelper helper = (CertStoreHelper)cache.get(type); CertStoreHelper helper = cache.get(type);
if (helper != null) { if (helper != null) {
return helper; return helper;
} }
......
...@@ -100,8 +100,7 @@ class URICertStore extends CertStoreSpi { ...@@ -100,8 +100,7 @@ class URICertStore extends CertStoreSpi {
private final CertificateFactory factory; private final CertificateFactory factory;
// cached Collection of X509Certificates (may be empty, never null) // cached Collection of X509Certificates (may be empty, never null)
private Collection<X509Certificate> certs = private Collection<X509Certificate> certs = Collections.emptySet();
Collections.<X509Certificate>emptySet();
// cached X509CRL (may be null) // cached X509CRL (may be null)
private X509CRL crl; private X509CRL crl;
...@@ -157,14 +156,14 @@ class URICertStore extends CertStoreSpi { ...@@ -157,14 +156,14 @@ class URICertStore extends CertStoreSpi {
* Returns a URI CertStore. This method consults a cache of * Returns a URI CertStore. This method consults a cache of
* CertStores (shared per JVM) using the URI as a key. * CertStores (shared per JVM) using the URI as a key.
*/ */
private static final Cache certStoreCache = private static final Cache<URICertStoreParameters, CertStore>
Cache.newSoftMemoryCache(CACHE_SIZE); certStoreCache = Cache.newSoftMemoryCache(CACHE_SIZE);
static synchronized CertStore getInstance(URICertStoreParameters params) static synchronized CertStore getInstance(URICertStoreParameters params)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
if (debug != null) { if (debug != null) {
debug.println("CertStore URI:" + params.uri); debug.println("CertStore URI:" + params.uri);
} }
CertStore ucs = (CertStore) certStoreCache.get(params); CertStore ucs = certStoreCache.get(params);
if (ucs == null) { if (ucs == null) {
ucs = new UCS(new URICertStore(params), null, "URI", params); ucs = new UCS(new URICertStore(params), null, "URI", params);
certStoreCache.put(params, ucs); certStoreCache.put(params, ucs);
...@@ -287,7 +286,7 @@ class URICertStore extends CertStoreSpi { ...@@ -287,7 +286,7 @@ class URICertStore extends CertStoreSpi {
} }
// exception, forget previous values // exception, forget previous values
lastModified = 0; lastModified = 0;
certs = Collections.<X509Certificate>emptySet(); certs = Collections.emptySet();
return certs; return certs;
} }
...@@ -394,7 +393,7 @@ class URICertStore extends CertStoreSpi { ...@@ -394,7 +393,7 @@ class URICertStore extends CertStoreSpi {
// exception, forget previous values // exception, forget previous values
lastModified = 0; lastModified = 0;
crl = null; crl = null;
return Collections.<X509CRL>emptyList(); return Collections.emptyList();
} }
/** /**
...@@ -404,9 +403,9 @@ class URICertStore extends CertStoreSpi { ...@@ -404,9 +403,9 @@ class URICertStore extends CertStoreSpi {
private static Collection<X509CRL> getMatchingCRLs private static Collection<X509CRL> getMatchingCRLs
(X509CRL crl, CRLSelector selector) { (X509CRL crl, CRLSelector selector) {
if (selector == null || (crl != null && selector.match(crl))) { if (selector == null || (crl != null && selector.match(crl))) {
return Collections.<X509CRL>singletonList(crl); return Collections.singletonList(crl);
} else { } else {
return Collections.<X509CRL>emptyList(); return Collections.emptyList();
} }
} }
......
/* /*
* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -79,7 +79,8 @@ public class X509CertificatePair { ...@@ -79,7 +79,8 @@ public class X509CertificatePair {
private X509Certificate reverse; private X509Certificate reverse;
private byte[] encoded; private byte[] encoded;
private static final Cache cache = Cache.newSoftMemoryCache(750); private static final Cache<Object, X509CertificatePair> cache
= Cache.newSoftMemoryCache(750);
/** /**
* Creates an empty instance of X509CertificatePair. * Creates an empty instance of X509CertificatePair.
...@@ -114,7 +115,7 @@ public class X509CertificatePair { ...@@ -114,7 +115,7 @@ public class X509CertificatePair {
* *
* For internal use only, external code should use generateCertificatePair. * For internal use only, external code should use generateCertificatePair.
*/ */
private X509CertificatePair(byte[] encoded)throws CertificateException { private X509CertificatePair(byte[] encoded) throws CertificateException {
try { try {
parse(new DerValue(encoded)); parse(new DerValue(encoded));
this.encoded = encoded; this.encoded = encoded;
...@@ -138,7 +139,7 @@ public class X509CertificatePair { ...@@ -138,7 +139,7 @@ public class X509CertificatePair {
public static synchronized X509CertificatePair generateCertificatePair public static synchronized X509CertificatePair generateCertificatePair
(byte[] encoded) throws CertificateException { (byte[] encoded) throws CertificateException {
Object key = new Cache.EqualByteArray(encoded); Object key = new Cache.EqualByteArray(encoded);
X509CertificatePair pair = (X509CertificatePair)cache.get(key); X509CertificatePair pair = cache.get(key);
if (pair != null) { if (pair != null) {
return pair; return pair;
} }
......
/* /*
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -160,7 +160,7 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -160,7 +160,7 @@ public final class LDAPCertStore extends CertStoreSpi {
*/ */
private boolean prefetchCRLs = false; private boolean prefetchCRLs = false;
private final Cache valueCache; private final Cache<String, byte[][]> valueCache;
private int cacheHits = 0; private int cacheHits = 0;
private int cacheMisses = 0; private int cacheMisses = 0;
...@@ -207,10 +207,11 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -207,10 +207,11 @@ public final class LDAPCertStore extends CertStoreSpi {
* Returns an LDAP CertStore. This method consults a cache of * Returns an LDAP CertStore. This method consults a cache of
* CertStores (shared per JVM) using the LDAP server/port as a key. * CertStores (shared per JVM) using the LDAP server/port as a key.
*/ */
private static final Cache certStoreCache = Cache.newSoftMemoryCache(185); private static final Cache<LDAPCertStoreParameters, CertStore>
certStoreCache = Cache.newSoftMemoryCache(185);
static synchronized CertStore getInstance(LDAPCertStoreParameters params) static synchronized CertStore getInstance(LDAPCertStoreParameters params)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
CertStore lcs = (CertStore) certStoreCache.get(params); CertStore lcs = certStoreCache.get(params);
if (lcs == null) { if (lcs == null) {
lcs = CertStore.getInstance("LDAP", params); lcs = CertStore.getInstance("LDAP", params);
certStoreCache.put(params, lcs); certStoreCache.put(params, lcs);
...@@ -232,7 +233,7 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -232,7 +233,7 @@ public final class LDAPCertStore extends CertStoreSpi {
private void createInitialDirContext(String server, int port) private void createInitialDirContext(String server, int port)
throws InvalidAlgorithmParameterException { throws InvalidAlgorithmParameterException {
String url = "ldap://" + server + ":" + port; String url = "ldap://" + server + ":" + port;
Hashtable<String,Object> env = new Hashtable<String,Object>(); Hashtable<String,Object> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory"); "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url); env.put(Context.PROVIDER_URL, url);
...@@ -283,7 +284,7 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -283,7 +284,7 @@ public final class LDAPCertStore extends CertStoreSpi {
LDAPRequest(String name) { LDAPRequest(String name) {
this.name = name; this.name = name;
requestedAttributes = new ArrayList<String>(5); requestedAttributes = new ArrayList<>(5);
} }
String getName() { String getName() {
...@@ -311,7 +312,7 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -311,7 +312,7 @@ public final class LDAPCertStore extends CertStoreSpi {
+ cacheMisses); + cacheMisses);
} }
String cacheKey = name + "|" + attrId; String cacheKey = name + "|" + attrId;
byte[][] values = (byte[][])valueCache.get(cacheKey); byte[][] values = valueCache.get(cacheKey);
if (values != null) { if (values != null) {
cacheHits++; cacheHits++;
return values; return values;
...@@ -347,7 +348,7 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -347,7 +348,7 @@ public final class LDAPCertStore extends CertStoreSpi {
System.out.println("LDAP requests: " + requests); System.out.println("LDAP requests: " + requests);
} }
} }
valueMap = new HashMap<String, byte[][]>(8); valueMap = new HashMap<>(8);
String[] attrIds = requestedAttributes.toArray(STRING0); String[] attrIds = requestedAttributes.toArray(STRING0);
Attributes attrs; Attributes attrs;
try { try {
...@@ -429,10 +430,10 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -429,10 +430,10 @@ public final class LDAPCertStore extends CertStoreSpi {
int n = encodedCert.length; int n = encodedCert.length;
if (n == 0) { if (n == 0) {
return Collections.<X509Certificate>emptySet(); return Collections.emptySet();
} }
List<X509Certificate> certs = new ArrayList<X509Certificate>(n); List<X509Certificate> certs = new ArrayList<>(n);
/* decode certs and check if they satisfy selector */ /* decode certs and check if they satisfy selector */
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]); ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]);
...@@ -477,11 +478,10 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -477,11 +478,10 @@ public final class LDAPCertStore extends CertStoreSpi {
int n = encodedCertPair.length; int n = encodedCertPair.length;
if (n == 0) { if (n == 0) {
return Collections.<X509CertificatePair>emptySet(); return Collections.emptySet();
} }
List<X509CertificatePair> certPairs = List<X509CertificatePair> certPairs = new ArrayList<>(n);
new ArrayList<X509CertificatePair>(n);
/* decode each cert pair and add it to the Collection */ /* decode each cert pair and add it to the Collection */
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
try { try {
...@@ -528,8 +528,7 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -528,8 +528,7 @@ public final class LDAPCertStore extends CertStoreSpi {
getCertPairs(request, CROSS_CERT); getCertPairs(request, CROSS_CERT);
// Find Certificates that match and put them in a list // Find Certificates that match and put them in a list
ArrayList<X509Certificate> matchingCerts = ArrayList<X509Certificate> matchingCerts = new ArrayList<>();
new ArrayList<X509Certificate>();
for (X509CertificatePair certPair : certPairs) { for (X509CertificatePair certPair : certPairs) {
X509Certificate cert; X509Certificate cert;
if (forward != null) { if (forward != null) {
...@@ -587,7 +586,7 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -587,7 +586,7 @@ public final class LDAPCertStore extends CertStoreSpi {
int basicConstraints = xsel.getBasicConstraints(); int basicConstraints = xsel.getBasicConstraints();
String subject = xsel.getSubjectAsString(); String subject = xsel.getSubjectAsString();
String issuer = xsel.getIssuerAsString(); String issuer = xsel.getIssuerAsString();
HashSet<X509Certificate> certs = new HashSet<X509Certificate>(); HashSet<X509Certificate> certs = new HashSet<>();
if (debug != null) { if (debug != null) {
debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: " debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: "
+ basicConstraints); + basicConstraints);
...@@ -706,10 +705,10 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -706,10 +705,10 @@ public final class LDAPCertStore extends CertStoreSpi {
int n = encodedCRL.length; int n = encodedCRL.length;
if (n == 0) { if (n == 0) {
return Collections.<X509CRL>emptySet(); return Collections.emptySet();
} }
List<X509CRL> crls = new ArrayList<X509CRL>(n); List<X509CRL> crls = new ArrayList<>(n);
/* decode each crl and check if it matches selector */ /* decode each crl and check if it matches selector */
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
try { try {
...@@ -765,13 +764,13 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -765,13 +764,13 @@ public final class LDAPCertStore extends CertStoreSpi {
throw new CertStoreException("need X509CRLSelector to find CRLs"); throw new CertStoreException("need X509CRLSelector to find CRLs");
} }
X509CRLSelector xsel = (X509CRLSelector) selector; X509CRLSelector xsel = (X509CRLSelector) selector;
HashSet<X509CRL> crls = new HashSet<X509CRL>(); HashSet<X509CRL> crls = new HashSet<>();
// Look in directory entry for issuer of cert we're checking. // Look in directory entry for issuer of cert we're checking.
Collection<Object> issuerNames; Collection<Object> issuerNames;
X509Certificate certChecking = xsel.getCertificateChecking(); X509Certificate certChecking = xsel.getCertificateChecking();
if (certChecking != null) { if (certChecking != null) {
issuerNames = new HashSet<Object>(); issuerNames = new HashSet<>();
X500Principal issuer = certChecking.getIssuerX500Principal(); X500Principal issuer = certChecking.getIssuerX500Principal();
issuerNames.add(issuer.getName(X500Principal.RFC2253)); issuerNames.add(issuer.getName(X500Principal.RFC2253));
} else { } else {
...@@ -796,7 +795,7 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -796,7 +795,7 @@ public final class LDAPCertStore extends CertStoreSpi {
issuerName = (String)nameObject; issuerName = (String)nameObject;
} }
// If all we want is CA certs, try to get the (probably shorter) ARL // If all we want is CA certs, try to get the (probably shorter) ARL
Collection<X509CRL> entryCRLs = Collections.<X509CRL>emptySet(); Collection<X509CRL> entryCRLs = Collections.emptySet();
if (certChecking == null || certChecking.getBasicConstraints() != -1) { if (certChecking == null || certChecking.getBasicConstraints() != -1) {
LDAPRequest request = new LDAPRequest(issuerName); LDAPRequest request = new LDAPRequest(issuerName);
request.addRequestedAttribute(CROSS_CERT); request.addRequestedAttribute(CROSS_CERT);
...@@ -1028,9 +1027,9 @@ public final class LDAPCertStore extends CertStoreSpi { ...@@ -1028,9 +1027,9 @@ public final class LDAPCertStore extends CertStoreSpi {
throws IOException { throws IOException {
this.selector = selector == null ? new X509CRLSelector() : selector; this.selector = selector == null ? new X509CRLSelector() : selector;
this.certIssuers = certIssuers; this.certIssuers = certIssuers;
issuerNames = new HashSet<Object>(); issuerNames = new HashSet<>();
issuerNames.add(ldapDN); issuerNames.add(ldapDN);
issuers = new HashSet<X500Principal>(); issuers = new HashSet<>();
issuers.add(new X500Name(ldapDN).asX500Principal()); issuers.add(new X500Name(ldapDN).asX500Principal());
} }
// we only override the get (accessor methods) since the set methods // we only override the get (accessor methods) since the set methods
......
/* /*
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -305,9 +305,11 @@ final class CipherBox { ...@@ -305,9 +305,11 @@ final class CipherBox {
byte[] buf = null; byte[] buf = null;
int limit = bb.limit(); int limit = bb.limit();
if (bb.hasArray()) { if (bb.hasArray()) {
int arrayOffset = bb.arrayOffset();
buf = bb.array(); buf = bb.array();
System.arraycopy(buf, pos, System.arraycopy(buf, arrayOffset + pos,
buf, pos + prefix.length, limit - pos); buf, arrayOffset + pos + prefix.length,
limit - pos);
bb.limit(limit + prefix.length); bb.limit(limit + prefix.length);
} else { } else {
buf = new byte[limit - pos]; buf = new byte[limit - pos];
...@@ -491,9 +493,10 @@ final class CipherBox { ...@@ -491,9 +493,10 @@ final class CipherBox {
byte[] buf = null; byte[] buf = null;
int limit = bb.limit(); int limit = bb.limit();
if (bb.hasArray()) { if (bb.hasArray()) {
int arrayOffset = bb.arrayOffset();
buf = bb.array(); buf = bb.array();
System.arraycopy(buf, pos + blockSize, System.arraycopy(buf, arrayOffset + pos + blockSize,
buf, pos, limit - pos - blockSize); buf, arrayOffset + pos, limit - pos - blockSize);
bb.limit(limit - blockSize); bb.limit(limit - blockSize);
} else { } else {
buf = new byte[limit - pos - blockSize]; buf = new byte[limit - pos - blockSize];
......
/* /*
* Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -43,11 +43,14 @@ import javax.net.ssl.SSLPeerUnverifiedException; ...@@ -43,11 +43,14 @@ import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSession;
import sun.security.util.Cache; import sun.security.util.Cache;
import sun.security.util.Cache.CacheVisitor;
final class SSLSessionContextImpl implements SSLSessionContext { final class SSLSessionContextImpl implements SSLSessionContext {
private Cache sessionCache; // session cache, session id as key private Cache<SessionId, SSLSessionImpl> sessionCache;
private Cache sessionHostPortCache; // session cache, "host:port" as key // session cache, session id as key
private Cache<String, SSLSessionImpl> sessionHostPortCache;
// session cache, "host:port" as key
private int cacheLimit; // the max cache size private int cacheLimit; // the max cache size
private int timeout; // timeout in seconds private int timeout; // timeout in seconds
...@@ -71,8 +74,7 @@ final class SSLSessionContextImpl implements SSLSessionContext { ...@@ -71,8 +74,7 @@ final class SSLSessionContextImpl implements SSLSessionContext {
throw new NullPointerException("session id cannot be null"); throw new NullPointerException("session id cannot be null");
} }
SSLSessionImpl sess = SSLSessionImpl sess = sessionCache.get(new SessionId(sessionId));
(SSLSessionImpl)sessionCache.get(new SessionId(sessionId));
if (!isTimedout(sess)) { if (!isTimedout(sess)) {
return sess; return sess;
} }
...@@ -157,8 +159,7 @@ final class SSLSessionContextImpl implements SSLSessionContext { ...@@ -157,8 +159,7 @@ final class SSLSessionContextImpl implements SSLSessionContext {
return null; return null;
} }
SSLSessionImpl sess = SSLSessionImpl sess = sessionHostPortCache.get(getKey(hostname, port));
(SSLSessionImpl)sessionHostPortCache.get(getKey(hostname, port));
if (!isTimedout(sess)) { if (!isTimedout(sess)) {
return sess; return sess;
} }
...@@ -193,7 +194,7 @@ final class SSLSessionContextImpl implements SSLSessionContext { ...@@ -193,7 +194,7 @@ final class SSLSessionContextImpl implements SSLSessionContext {
// package-private method, remove a cached SSLSession // package-private method, remove a cached SSLSession
void remove(SessionId key) { void remove(SessionId key) {
SSLSessionImpl s = (SSLSessionImpl)sessionCache.get(key); SSLSessionImpl s = sessionCache.get(key);
if (s != null) { if (s != null) {
sessionCache.remove(key); sessionCache.remove(key);
sessionHostPortCache.remove( sessionHostPortCache.remove(
...@@ -233,17 +234,17 @@ final class SSLSessionContextImpl implements SSLSessionContext { ...@@ -233,17 +234,17 @@ final class SSLSessionContextImpl implements SSLSessionContext {
} }
final class SessionCacheVisitor final class SessionCacheVisitor
implements sun.security.util.Cache.CacheVisitor { implements Cache.CacheVisitor<SessionId, SSLSessionImpl> {
Vector<byte[]> ids = null; Vector<byte[]> ids = null;
// public void visit(java.util.Map<Object, Object> map) {} // public void visit(java.util.Map<K,V> map) {}
public void visit(java.util.Map<Object, Object> map) { public void visit(java.util.Map<SessionId, SSLSessionImpl> map) {
ids = new Vector<byte[]>(map.size()); ids = new Vector<>(map.size());
for (Object key : map.keySet()) { for (SessionId key : map.keySet()) {
SSLSessionImpl value = (SSLSessionImpl)map.get(key); SSLSessionImpl value = map.get(key);
if (!isTimedout(value)) { if (!isTimedout(value)) {
ids.addElement(((SessionId)key).getId()); ids.addElement(key.getId());
} }
} }
} }
......
...@@ -43,7 +43,7 @@ import java.lang.ref.*; ...@@ -43,7 +43,7 @@ import java.lang.ref.*;
* *
* . optional lifetime, specified in seconds. * . optional lifetime, specified in seconds.
* *
* . save for concurrent use by multiple threads * . safe for concurrent use by multiple threads
* *
* . values are held by either standard references or via SoftReferences. * . values are held by either standard references or via SoftReferences.
* SoftReferences have the advantage that they are automatically cleared * SoftReferences have the advantage that they are automatically cleared
...@@ -69,7 +69,7 @@ import java.lang.ref.*; ...@@ -69,7 +69,7 @@ import java.lang.ref.*;
* *
* @author Andreas Sterbenz * @author Andreas Sterbenz
*/ */
public abstract class Cache { public abstract class Cache<K,V> {
protected Cache() { protected Cache() {
// empty // empty
...@@ -88,12 +88,12 @@ public abstract class Cache { ...@@ -88,12 +88,12 @@ public abstract class Cache {
/** /**
* Add an entry to the cache. * Add an entry to the cache.
*/ */
public abstract void put(Object key, Object value); public abstract void put(K key, V value);
/** /**
* Get a value from the cache. * Get a value from the cache.
*/ */
public abstract Object get(Object key); public abstract V get(Object key);
/** /**
* Remove an entry from the cache. * Remove an entry from the cache.
...@@ -113,14 +113,14 @@ public abstract class Cache { ...@@ -113,14 +113,14 @@ public abstract class Cache {
/** /**
* accept a visitor * accept a visitor
*/ */
public abstract void accept(CacheVisitor visitor); public abstract void accept(CacheVisitor<K,V> visitor);
/** /**
* Return a new memory cache with the specified maximum size, unlimited * Return a new memory cache with the specified maximum size, unlimited
* lifetime for entries, with the values held by SoftReferences. * lifetime for entries, with the values held by SoftReferences.
*/ */
public static Cache newSoftMemoryCache(int size) { public static <K,V> Cache<K,V> newSoftMemoryCache(int size) {
return new MemoryCache(true, size); return new MemoryCache<>(true, size);
} }
/** /**
...@@ -128,23 +128,24 @@ public abstract class Cache { ...@@ -128,23 +128,24 @@ public abstract class Cache {
* specified maximum lifetime (in seconds), with the values held * specified maximum lifetime (in seconds), with the values held
* by SoftReferences. * by SoftReferences.
*/ */
public static Cache newSoftMemoryCache(int size, int timeout) { public static <K,V> Cache<K,V> newSoftMemoryCache(int size, int timeout) {
return new MemoryCache(true, size, timeout); return new MemoryCache<>(true, size, timeout);
} }
/** /**
* Return a new memory cache with the specified maximum size, unlimited * Return a new memory cache with the specified maximum size, unlimited
* lifetime for entries, with the values held by standard references. * lifetime for entries, with the values held by standard references.
*/ */
public static Cache newHardMemoryCache(int size) { public static <K,V> Cache<K,V> newHardMemoryCache(int size) {
return new MemoryCache(false, size); return new MemoryCache<>(false, size);
} }
/** /**
* Return a dummy cache that does nothing. * Return a dummy cache that does nothing.
*/ */
public static Cache newNullCache() { @SuppressWarnings("unchecked")
return NullCache.INSTANCE; public static <K,V> Cache<K,V> newNullCache() {
return (Cache<K,V>) NullCache.INSTANCE;
} }
/** /**
...@@ -152,8 +153,8 @@ public abstract class Cache { ...@@ -152,8 +153,8 @@ public abstract class Cache {
* specified maximum lifetime (in seconds), with the values held * specified maximum lifetime (in seconds), with the values held
* by standard references. * by standard references.
*/ */
public static Cache newHardMemoryCache(int size, int timeout) { public static <K,V> Cache<K,V> newHardMemoryCache(int size, int timeout) {
return new MemoryCache(false, size, timeout); return new MemoryCache<>(false, size, timeout);
} }
/** /**
...@@ -193,15 +194,15 @@ public abstract class Cache { ...@@ -193,15 +194,15 @@ public abstract class Cache {
} }
} }
public interface CacheVisitor { public interface CacheVisitor<K,V> {
public void visit(Map<Object, Object> map); public void visit(Map<K,V> map);
} }
} }
class NullCache extends Cache { class NullCache<K,V> extends Cache<K,V> {
final static Cache INSTANCE = new NullCache(); final static Cache<Object,Object> INSTANCE = new NullCache<>();
private NullCache() { private NullCache() {
// empty // empty
...@@ -215,11 +216,11 @@ class NullCache extends Cache { ...@@ -215,11 +216,11 @@ class NullCache extends Cache {
// empty // empty
} }
public void put(Object key, Object value) { public void put(K key, V value) {
// empty // empty
} }
public Object get(Object key) { public V get(Object key) {
return null; return null;
} }
...@@ -235,23 +236,26 @@ class NullCache extends Cache { ...@@ -235,23 +236,26 @@ class NullCache extends Cache {
// empty // empty
} }
public void accept(CacheVisitor visitor) { public void accept(CacheVisitor<K,V> visitor) {
// empty // empty
} }
} }
class MemoryCache extends Cache { class MemoryCache<K,V> extends Cache<K,V> {
private final static float LOAD_FACTOR = 0.75f; private final static float LOAD_FACTOR = 0.75f;
// XXXX // XXXX
private final static boolean DEBUG = false; private final static boolean DEBUG = false;
private final Map<Object, CacheEntry> cacheMap; private final Map<K, CacheEntry<K,V>> cacheMap;
private int maxSize; private int maxSize;
private long lifetime; private long lifetime;
private final ReferenceQueue<Object> queue;
// ReferenceQueue is of type V instead of Cache<K,V>
// to allow SoftCacheEntry to extend SoftReference<V>
private final ReferenceQueue<V> queue;
public MemoryCache(boolean soft, int maxSize) { public MemoryCache(boolean soft, int maxSize) {
this(soft, maxSize, 0); this(soft, maxSize, 0);
...@@ -260,10 +264,13 @@ class MemoryCache extends Cache { ...@@ -260,10 +264,13 @@ class MemoryCache extends Cache {
public MemoryCache(boolean soft, int maxSize, int lifetime) { public MemoryCache(boolean soft, int maxSize, int lifetime) {
this.maxSize = maxSize; this.maxSize = maxSize;
this.lifetime = lifetime * 1000; this.lifetime = lifetime * 1000;
this.queue = soft ? new ReferenceQueue<Object>() : null; if (soft)
this.queue = new ReferenceQueue<>();
else
this.queue = null;
int buckets = (int)(maxSize / LOAD_FACTOR) + 1; int buckets = (int)(maxSize / LOAD_FACTOR) + 1;
cacheMap = new LinkedHashMap<Object, CacheEntry>(buckets, cacheMap = new LinkedHashMap<>(buckets, LOAD_FACTOR, true);
LOAD_FACTOR, true);
} }
/** /**
...@@ -279,16 +286,17 @@ class MemoryCache extends Cache { ...@@ -279,16 +286,17 @@ class MemoryCache extends Cache {
} }
int startSize = cacheMap.size(); int startSize = cacheMap.size();
while (true) { while (true) {
CacheEntry entry = (CacheEntry)queue.poll(); @SuppressWarnings("unchecked")
CacheEntry<K,V> entry = (CacheEntry<K,V>)queue.poll();
if (entry == null) { if (entry == null) {
break; break;
} }
Object key = entry.getKey(); K key = entry.getKey();
if (key == null) { if (key == null) {
// key is null, entry has already been removed // key is null, entry has already been removed
continue; continue;
} }
CacheEntry currentEntry = cacheMap.remove(key); CacheEntry<K,V> currentEntry = cacheMap.remove(key);
// check if the entry in the map corresponds to the expired // check if the entry in the map corresponds to the expired
// entry. If not, readd the entry // entry. If not, readd the entry
if ((currentEntry != null) && (entry != currentEntry)) { if ((currentEntry != null) && (entry != currentEntry)) {
...@@ -314,9 +322,9 @@ class MemoryCache extends Cache { ...@@ -314,9 +322,9 @@ class MemoryCache extends Cache {
} }
int cnt = 0; int cnt = 0;
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
for (Iterator<CacheEntry> t = cacheMap.values().iterator(); for (Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
t.hasNext(); ) { t.hasNext(); ) {
CacheEntry entry = t.next(); CacheEntry<K,V> entry = t.next();
if (entry.isValid(time) == false) { if (entry.isValid(time) == false) {
t.remove(); t.remove();
cnt++; cnt++;
...@@ -339,7 +347,7 @@ class MemoryCache extends Cache { ...@@ -339,7 +347,7 @@ class MemoryCache extends Cache {
if (queue != null) { if (queue != null) {
// if this is a SoftReference cache, first invalidate() all // if this is a SoftReference cache, first invalidate() all
// entries so that GC does not have to enqueue them // entries so that GC does not have to enqueue them
for (CacheEntry entry : cacheMap.values()) { for (CacheEntry<K,V> entry : cacheMap.values()) {
entry.invalidate(); entry.invalidate();
} }
while (queue.poll() != null) { while (queue.poll() != null) {
...@@ -349,12 +357,12 @@ class MemoryCache extends Cache { ...@@ -349,12 +357,12 @@ class MemoryCache extends Cache {
cacheMap.clear(); cacheMap.clear();
} }
public synchronized void put(Object key, Object value) { public synchronized void put(K key, V value) {
emptyQueue(); emptyQueue();
long expirationTime = (lifetime == 0) ? 0 : long expirationTime = (lifetime == 0) ? 0 :
System.currentTimeMillis() + lifetime; System.currentTimeMillis() + lifetime;
CacheEntry newEntry = newEntry(key, value, expirationTime, queue); CacheEntry<K,V> newEntry = newEntry(key, value, expirationTime, queue);
CacheEntry oldEntry = cacheMap.put(key, newEntry); CacheEntry<K,V> oldEntry = cacheMap.put(key, newEntry);
if (oldEntry != null) { if (oldEntry != null) {
oldEntry.invalidate(); oldEntry.invalidate();
return; return;
...@@ -362,8 +370,8 @@ class MemoryCache extends Cache { ...@@ -362,8 +370,8 @@ class MemoryCache extends Cache {
if (maxSize > 0 && cacheMap.size() > maxSize) { if (maxSize > 0 && cacheMap.size() > maxSize) {
expungeExpiredEntries(); expungeExpiredEntries();
if (cacheMap.size() > maxSize) { // still too large? if (cacheMap.size() > maxSize) { // still too large?
Iterator<CacheEntry> t = cacheMap.values().iterator(); Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
CacheEntry lruEntry = t.next(); CacheEntry<K,V> lruEntry = t.next();
if (DEBUG) { if (DEBUG) {
System.out.println("** Overflow removal " System.out.println("** Overflow removal "
+ lruEntry.getKey() + " | " + lruEntry.getValue()); + lruEntry.getKey() + " | " + lruEntry.getValue());
...@@ -374,9 +382,9 @@ class MemoryCache extends Cache { ...@@ -374,9 +382,9 @@ class MemoryCache extends Cache {
} }
} }
public synchronized Object get(Object key) { public synchronized V get(Object key) {
emptyQueue(); emptyQueue();
CacheEntry entry = cacheMap.get(key); CacheEntry<K,V> entry = cacheMap.get(key);
if (entry == null) { if (entry == null) {
return null; return null;
} }
...@@ -393,7 +401,7 @@ class MemoryCache extends Cache { ...@@ -393,7 +401,7 @@ class MemoryCache extends Cache {
public synchronized void remove(Object key) { public synchronized void remove(Object key) {
emptyQueue(); emptyQueue();
CacheEntry entry = cacheMap.remove(key); CacheEntry<K,V> entry = cacheMap.remove(key);
if (entry != null) { if (entry != null) {
entry.invalidate(); entry.invalidate();
} }
...@@ -402,9 +410,9 @@ class MemoryCache extends Cache { ...@@ -402,9 +410,9 @@ class MemoryCache extends Cache {
public synchronized void setCapacity(int size) { public synchronized void setCapacity(int size) {
expungeExpiredEntries(); expungeExpiredEntries();
if (size > 0 && cacheMap.size() > size) { if (size > 0 && cacheMap.size() > size) {
Iterator<CacheEntry> t = cacheMap.values().iterator(); Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
for (int i = cacheMap.size() - size; i > 0; i--) { for (int i = cacheMap.size() - size; i > 0; i--) {
CacheEntry lruEntry = t.next(); CacheEntry<K,V> lruEntry = t.next();
if (DEBUG) { if (DEBUG) {
System.out.println("** capacity reset removal " System.out.println("** capacity reset removal "
+ lruEntry.getKey() + " | " + lruEntry.getValue()); + lruEntry.getKey() + " | " + lruEntry.getValue());
...@@ -431,60 +439,61 @@ class MemoryCache extends Cache { ...@@ -431,60 +439,61 @@ class MemoryCache extends Cache {
} }
// it is a heavyweight method. // it is a heavyweight method.
public synchronized void accept(CacheVisitor visitor) { public synchronized void accept(CacheVisitor<K,V> visitor) {
expungeExpiredEntries(); expungeExpiredEntries();
Map<Object, Object> cached = getCachedEntries(); Map<K,V> cached = getCachedEntries();
visitor.visit(cached); visitor.visit(cached);
} }
private Map<Object, Object> getCachedEntries() { private Map<K,V> getCachedEntries() {
Map<Object,Object> kvmap = new HashMap<Object,Object>(cacheMap.size()); Map<K,V> kvmap = new HashMap<>(cacheMap.size());
for (CacheEntry entry : cacheMap.values()) { for (CacheEntry<K,V> entry : cacheMap.values()) {
kvmap.put(entry.getKey(), entry.getValue()); kvmap.put(entry.getKey(), entry.getValue());
} }
return kvmap; return kvmap;
} }
protected CacheEntry newEntry(Object key, Object value, protected CacheEntry<K,V> newEntry(K key, V value,
long expirationTime, ReferenceQueue<Object> queue) { long expirationTime, ReferenceQueue<V> queue) {
if (queue != null) { if (queue != null) {
return new SoftCacheEntry(key, value, expirationTime, queue); return new SoftCacheEntry<>(key, value, expirationTime, queue);
} else { } else {
return new HardCacheEntry(key, value, expirationTime); return new HardCacheEntry<>(key, value, expirationTime);
} }
} }
private static interface CacheEntry { private static interface CacheEntry<K,V> {
boolean isValid(long currentTime); boolean isValid(long currentTime);
void invalidate(); void invalidate();
Object getKey(); K getKey();
Object getValue(); V getValue();
} }
private static class HardCacheEntry implements CacheEntry { private static class HardCacheEntry<K,V> implements CacheEntry<K,V> {
private Object key, value; private K key;
private V value;
private long expirationTime; private long expirationTime;
HardCacheEntry(Object key, Object value, long expirationTime) { HardCacheEntry(K key, V value, long expirationTime) {
this.key = key; this.key = key;
this.value = value; this.value = value;
this.expirationTime = expirationTime; this.expirationTime = expirationTime;
} }
public Object getKey() { public K getKey() {
return key; return key;
} }
public Object getValue() { public V getValue() {
return value; return value;
} }
...@@ -503,24 +512,25 @@ class MemoryCache extends Cache { ...@@ -503,24 +512,25 @@ class MemoryCache extends Cache {
} }
} }
private static class SoftCacheEntry private static class SoftCacheEntry<K,V>
extends SoftReference<Object> implements CacheEntry { extends SoftReference<V>
implements CacheEntry<K,V> {
private Object key; private K key;
private long expirationTime; private long expirationTime;
SoftCacheEntry(Object key, Object value, long expirationTime, SoftCacheEntry(K key, V value, long expirationTime,
ReferenceQueue<Object> queue) { ReferenceQueue<V> queue) {
super(value, queue); super(value, queue);
this.key = key; this.key = key;
this.expirationTime = expirationTime; this.expirationTime = expirationTime;
} }
public Object getKey() { public K getKey() {
return key; return key;
} }
public Object getValue() { public V getValue() {
return get(); return get();
} }
......
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7031830
* @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine
* @run main/othervm SSLEngineBadBufferArrayAccess
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
*/
/**
* A SSLSocket/SSLEngine interop test case. This is not the way to
* code SSLEngine-based servers, but works for what we need to do here,
* which is to make sure that SSLEngine/SSLSockets can talk to each other.
* SSLEngines can use direct or indirect buffers, and different code
* is used to get at the buffer contents internally, so we test that here.
*
* The test creates one SSLSocket (client) and one SSLEngine (server).
* The SSLSocket talks to a raw ServerSocket, and the server code
* does the translation between byte [] and ByteBuffers that the SSLEngine
* can use. The "transport" layer consists of a Socket Input/OutputStream
* and two byte buffers for the SSLEngines: think of them
* as directly connected pipes.
*
* Again, this is a *very* simple example: real code will be much more
* involved. For example, different threading and I/O models could be
* used, transport mechanisms could close unexpectedly, and so on.
*
* When this application runs, notice that several messages
* (wrap/unwrap) pass before any application data is consumed or
* produced. (For more information, please see the SSL/TLS
* specifications.) There may several steps for a successful handshake,
* so it's typical to see the following series of operations:
*
* client server message
* ====== ====== =======
* write() ... ClientHello
* ... unwrap() ClientHello
* ... wrap() ServerHello/Certificate
* read() ... ServerHello/Certificate
* write() ... ClientKeyExchange
* write() ... ChangeCipherSpec
* write() ... Finished
* ... unwrap() ClientKeyExchange
* ... unwrap() ChangeCipherSpec
* ... unwrap() Finished
* ... wrap() ChangeCipherSpec
* ... wrap() Finished
* read() ... ChangeCipherSpec
* read() ... Finished
*
* This particular bug had a problem where byte buffers backed by an
* array didn't offset correctly, and we got bad MAC errors.
*/
import javax.net.ssl.*;
import javax.net.ssl.SSLEngineResult.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.nio.*;
public class SSLEngineBadBufferArrayAccess {
/*
* Enables logging of the SSL/TLS operations.
*/
private static boolean logging = true;
/*
* Enables the JSSE system debugging system property:
*
* -Djavax.net.debug=all
*
* This gives a lot of low-level information about operations underway,
* including specific handshake messages, and might be best examined
* after gaining some familiarity with this application.
*/
private static boolean debug = false;
private SSLContext sslc;
private SSLEngine serverEngine; // server-side SSLEngine
private SSLSocket sslSocket; // client-side socket
private ServerSocket serverSocket; // server-side Socket, generates the...
private Socket socket; // server-side socket that will read
private final byte[] serverMsg = "Hi there Client, I'm a Server".getBytes();
private final byte[] clientMsg = "Hello Server, I'm a Client".getBytes();
private ByteBuffer serverOut; // write side of serverEngine
private ByteBuffer serverIn; // read side of serverEngine
private volatile Exception clientException;
private volatile Exception serverException;
/*
* For data transport, this example uses local ByteBuffers.
*/
private ByteBuffer cTOs; // "reliable" transport client->server
private ByteBuffer sTOc; // "reliable" transport server->client
/*
* The following is to set up the keystores/trust material.
*/
private static final String pathToStores = "../../../../../../../etc/";
private static final String keyStoreFile = "keystore";
private static final String trustStoreFile = "truststore";
private static final String passwd = "passphrase";
private static String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores
+ "/" + keyStoreFile;
private static String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores
+ "/" + trustStoreFile;
/*
* Main entry point for this test.
*/
public static void main(String args[]) throws Exception {
if (debug) {
System.setProperty("javax.net.debug", "all");
}
String [] protocols = new String [] {
"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" };
for (String protocol : protocols) {
log("Testing " + protocol);
/*
* Run the tests with direct and indirect buffers.
*/
SSLEngineBadBufferArrayAccess test =
new SSLEngineBadBufferArrayAccess(protocol);
test.runTest(true);
test.runTest(false);
}
System.out.println("Test Passed.");
}
/*
* Create an initialized SSLContext to use for these tests.
*/
public SSLEngineBadBufferArrayAccess(String protocol) throws Exception {
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore ts = KeyStore.getInstance("JKS");
char[] passphrase = "passphrase".toCharArray();
ks.load(new FileInputStream(keyFilename), passphrase);
ts.load(new FileInputStream(trustFilename), passphrase);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslCtx = SSLContext.getInstance(protocol);
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
sslc = sslCtx;
}
/*
* Run the test.
*
* Sit in a tight loop, with the server engine calling wrap/unwrap
* regardless of whether data is available or not. We do this until
* we get the application data. Then we shutdown and go to the next one.
*
* The main loop handles all of the I/O phases of the SSLEngine's
* lifetime:
*
* initial handshaking
* application data transfer
* engine closing
*
* One could easily separate these phases into separate
* sections of code.
*/
private void runTest(boolean direct) throws Exception {
boolean serverClose = direct;
serverSocket = new ServerSocket(0);
int port = serverSocket.getLocalPort();
Thread thread = createClientThread(port, serverClose);
socket = serverSocket.accept();
socket.setSoTimeout(500);
serverSocket.close();
createSSLEngine();
createBuffers(direct);
try {
boolean closed = false;
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
SSLEngineResult serverResult; // results from last operation
/*
* Examining the SSLEngineResults could be much more involved,
* and may alter the overall flow of the application.
*
* For example, if we received a BUFFER_OVERFLOW when trying
* to write to the output pipe, we could reallocate a larger
* pipe, but instead we wait for the peer to drain it.
*/
byte[] inbound = new byte[8192];
byte[] outbound = new byte[8192];
while (!isEngineClosed(serverEngine)) {
int len = 0;
// Inbound data
log("================");
// Read from the Client side.
try {
len = is.read(inbound);
if (len == -1) {
throw new Exception("Unexpected EOF");
}
cTOs.put(inbound, 0, len);
} catch (SocketTimeoutException ste) {
// swallow. Nothing yet, probably waiting on us.
}
cTOs.flip();
serverResult = serverEngine.unwrap(cTOs, serverIn);
log("server unwrap: ", serverResult);
runDelegatedTasks(serverResult, serverEngine);
cTOs.compact();
// Outbound data
log("----");
serverResult = serverEngine.wrap(serverOut, sTOc);
log("server wrap: ", serverResult);
runDelegatedTasks(serverResult, serverEngine);
sTOc.flip();
if ((len = sTOc.remaining()) != 0) {
sTOc.get(outbound, 0, len);
os.write(outbound, 0, len);
// Give the other side a chance to process
}
sTOc.compact();
if (!closed && (serverOut.remaining() == 0)) {
closed = true;
/*
* We'll alternate initiatating the shutdown.
* When the server initiates, it will take one more
* loop, but tests the orderly shutdown.
*/
if (serverClose) {
serverEngine.closeOutbound();
}
serverIn.flip();
/*
* A sanity check to ensure we got what was sent.
*/
if (serverIn.remaining() != clientMsg.length) {
throw new Exception("Client: Data length error");
}
for (int i = 0; i < clientMsg.length; i++) {
if (clientMsg[i] != serverIn.get()) {
throw new Exception("Client: Data content error");
}
}
serverIn.compact();
}
}
return;
} catch (Exception e) {
serverException = e;
} finally {
socket.close();
// Wait for the client to join up with us.
thread.join();
if (serverException != null) {
throw serverException;
}
if (clientException != null) {
throw clientException;
}
}
}
/*
* Create a client thread which does simple SSLSocket operations.
* We'll write and read one data packet.
*/
private Thread createClientThread(final int port,
final boolean serverClose) throws Exception {
Thread t = new Thread("ClientThread") {
@Override
public void run() {
try {
Thread.sleep(1000); // Give server time to finish setup.
sslSocket = (SSLSocket) sslc.getSocketFactory().
createSocket("localhost", port);
OutputStream os = sslSocket.getOutputStream();
InputStream is = sslSocket.getInputStream();
// write(byte[]) goes in one shot.
os.write(clientMsg);
byte[] inbound = new byte[2048];
int pos = 0;
int len;
done:
while ((len = is.read(inbound, pos, 2048 - pos)) != -1) {
pos += len;
// Let the client do the closing.
if ((pos == serverMsg.length) && !serverClose) {
sslSocket.close();
break done;
}
}
if (pos != serverMsg.length) {
throw new Exception("Client: Data length error");
}
for (int i = 0; i < serverMsg.length; i++) {
if (inbound[i] != serverMsg[i]) {
throw new Exception("Client: Data content error");
}
}
} catch (Exception e) {
clientException = e;
}
}
};
t.start();
return t;
}
/*
* Using the SSLContext created during object creation,
* create/configure the SSLEngines we'll use for this test.
*/
private void createSSLEngine() throws Exception {
/*
* Configure the serverEngine to act as a server in the SSL/TLS
* handshake.
*/
serverEngine = sslc.createSSLEngine();
serverEngine.setUseClientMode(false);
serverEngine.getNeedClientAuth();
}
/*
* Create and size the buffers appropriately.
*/
private void createBuffers(boolean direct) {
SSLSession session = serverEngine.getSession();
int appBufferMax = session.getApplicationBufferSize();
int netBufferMax = session.getPacketBufferSize();
/*
* We'll make the input buffers a bit bigger than the max needed
* size, so that unwrap()s following a successful data transfer
* won't generate BUFFER_OVERFLOWS.
*
* We'll use a mix of direct and indirect ByteBuffers for
* tutorial purposes only. In reality, only use direct
* ByteBuffers when they give a clear performance enhancement.
*/
if (direct) {
serverIn = ByteBuffer.allocateDirect(appBufferMax + 50);
cTOs = ByteBuffer.allocateDirect(netBufferMax);
sTOc = ByteBuffer.allocateDirect(netBufferMax);
} else {
serverIn = ByteBuffer.allocate(appBufferMax + 50);
cTOs = ByteBuffer.allocate(netBufferMax);
sTOc = ByteBuffer.allocate(netBufferMax);
}
serverOut = ByteBuffer.wrap(serverMsg);
}
/*
* If the result indicates that we have outstanding tasks to do,
* go ahead and run them in this thread.
*/
private static void runDelegatedTasks(SSLEngineResult result,
SSLEngine engine) throws Exception {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
log("\trunning delegated task...");
runnable.run();
}
HandshakeStatus hsStatus = engine.getHandshakeStatus();
if (hsStatus == HandshakeStatus.NEED_TASK) {
throw new Exception(
"handshake shouldn't need additional tasks");
}
log("\tnew HandshakeStatus: " + hsStatus);
}
}
private static boolean isEngineClosed(SSLEngine engine) {
return (engine.isOutboundDone() && engine.isInboundDone());
}
/*
* Logging code
*/
private static boolean resultOnce = true;
private static void log(String str, SSLEngineResult result) {
if (!logging) {
return;
}
if (resultOnce) {
resultOnce = false;
System.out.println("The format of the SSLEngineResult is: \n"
+ "\t\"getStatus() / getHandshakeStatus()\" +\n"
+ "\t\"bytesConsumed() / bytesProduced()\"\n");
}
HandshakeStatus hsStatus = result.getHandshakeStatus();
log(str
+ result.getStatus() + "/" + hsStatus + ", "
+ result.bytesConsumed() + "/" + result.bytesProduced()
+ " bytes");
if (hsStatus == HandshakeStatus.FINISHED) {
log("\t...ready for application data");
}
}
private static void log(String str) {
if (logging) {
System.out.println(str);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册