From 12e10c1c6f9324693b1dad96ab57fada2b771f11 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Mon, 16 Aug 2010 15:28:32 -0700 Subject: [PATCH] b/2914872: fix concurrent initialization problem with peer certificate chain fields Change-Id: Ib76dd826c8f3616d4a3aed608aef432a1b99f3d6 --- .../xnet/provider/jsse/OpenSSLSessionImpl.java | 99 +++++++++++++--------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java index 1927f2e0..498e923a 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java @@ -43,11 +43,11 @@ public class OpenSSLSessionImpl implements SSLSession { private long creationTime = 0; long lastAccessedTime = 0; X509Certificate[] localCertificates; - X509Certificate[] peerCertificates; + volatile X509Certificate[] peerCertificates; private boolean isValid = true; private TwoKeyHashMap values = new TwoKeyHashMap(); - private javax.security.cert.X509Certificate[] peerCertificateChain; + private volatile javax.security.cert.X509Certificate[] peerCertificateChain; protected int sslSessionNativePointer; private String peerHost; private int peerPort = -1; @@ -205,28 +205,37 @@ public class OpenSSLSessionImpl implements SSLSession { */ public javax.security.cert.X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { - if (peerCertificateChain == null) { - try { - byte[][] bytes - = NativeCrypto.SSL_SESSION_get_peer_cert_chain( - sessionContext.sslCtxNativePointer, sslSessionNativePointer); - if (bytes == null) { - throw new SSLPeerUnverifiedException("No certificate available"); - } - - peerCertificateChain = new javax.security.cert.X509Certificate[bytes.length]; - - for(int i = 0; i < bytes.length; i++) { - peerCertificateChain[i] - = javax.security.cert.X509Certificate.getInstance(bytes[i]); - } - - return peerCertificateChain; - } catch (javax.security.cert.CertificateException e) { - throw new SSLPeerUnverifiedException(e.getMessage()); + javax.security.cert.X509Certificate[] result = peerCertificateChain; + if (result == null) { + // single-check idiom + peerCertificateChain = result = createPeerCertificateChain(); + } + return result; + } + + /** + * Provide a value to initialize the volatile peerCertificateChain + * field based on the native SSL_SESSION + */ + private javax.security.cert.X509Certificate[] createPeerCertificateChain() + throws SSLPeerUnverifiedException { + try { + byte[][] bytes + = NativeCrypto.SSL_SESSION_get_peer_cert_chain( + sessionContext.sslCtxNativePointer, sslSessionNativePointer); + if (bytes == null) { + throw new SSLPeerUnverifiedException("No certificate available"); } - } else { - return peerCertificateChain; + + javax.security.cert.X509Certificate[] chain + = new javax.security.cert.X509Certificate[bytes.length]; + + for (int i = 0; i < bytes.length; i++) { + chain[i] = javax.security.cert.X509Certificate.getInstance(bytes[i]); + } + return chain; + } catch (javax.security.cert.CertificateException e) { + throw new SSLPeerUnverifiedException(e.getMessage()); } } @@ -241,25 +250,33 @@ public class OpenSSLSessionImpl implements SSLSession { * could not be verified. */ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { - if (peerCertificates == null) { - if (peerCertificateChain == null) getPeerCertificateChain(); - try { - if (peerCertificateChain.length == 0) return new X509Certificate[]{}; - - peerCertificates = new X509CertImpl[peerCertificateChain.length]; - for(int i = 0; i < peerCertificates.length; i++) { - peerCertificates[i] = new X509CertImpl(peerCertificateChain[i].getEncoded()); - } - return peerCertificates; - } catch (SSLPeerUnverifiedException e) { - return new X509Certificate[]{}; - } catch (IOException e) { - return new X509Certificate[]{}; - } catch (CertificateEncodingException e) { - return new X509Certificate[]{}; + X509Certificate[] result = peerCertificates; + if (result == null) { + // single-check idiom + peerCertificates = result = createPeerCertificates(); + } + return result; + } + + /** + * Provide a value to initialize the volatile peerCertificates + * field based on the peerCertificateChain field + */ + private X509Certificate[] createPeerCertificates() throws SSLPeerUnverifiedException { + getPeerCertificateChain(); + try { + X509Certificate[] certificates = new X509CertImpl[peerCertificateChain.length]; + for (int i = 0; i < certificates.length; i++) { + byte[] encoded = peerCertificateChain[i].getEncoded(); + certificates[i] = new X509CertImpl(encoded); } - } else { - return peerCertificates; + return certificates; + } catch (SSLPeerUnverifiedException e) { + return new X509Certificate[]{}; + } catch (IOException e) { + return new X509Certificate[]{}; + } catch (CertificateEncodingException e) { + return new X509Certificate[]{}; } } -- 2.11.0