MD2InTrustAnchor.java revision 13528:90fc355d014a
178828Sobrien/* 233965Sjdp * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3130561Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 478828Sobrien * 578828Sobrien * This code is free software; you can redistribute it and/or modify it 678828Sobrien * under the terms of the GNU General Public License version 2 only, as 778828Sobrien * published by the Free Software Foundation. Oracle designates this 878828Sobrien * particular file as subject to the "Classpath" exception as provided 978828Sobrien * by Oracle in the LICENSE file that accompanied this code. 1078828Sobrien * 1178828Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT 1278828Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1378828Sobrien * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1478828Sobrien * version 2 for more details (a copy is included in the LICENSE file that 1578828Sobrien * accompanied this code). 1678828Sobrien * 1778828Sobrien * You should have received a copy of the GNU General Public License version 1878828Sobrien * 2 along with this work; if not, write to the Free Software Foundation, 1933965Sjdp * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2033965Sjdp * 2133965Sjdp * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22130561Sobrien * or visit www.oracle.com if you need additional information or have any 23130561Sobrien * questions. 24130561Sobrien */ 2533965Sjdp 26130561Sobrien// 27130561Sobrien// SunJSSE does not support dynamic system properties, no way to re-use 2833965Sjdp// system properties in samevm/agentvm mode. 2933965Sjdp// 3033965Sjdp 31130561Sobrien/* 32130561Sobrien * @test 33130561Sobrien * @bug 7113275 34130561Sobrien * @summary compatibility issue with MD2 trust anchor and old X509TrustManager 35130561Sobrien * @run main/othervm MD2InTrustAnchor PKIX TLSv1.1 36130561Sobrien * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.1 37130561Sobrien * @run main/othervm MD2InTrustAnchor PKIX TLSv1.2 38130561Sobrien * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.2 3933965Sjdp */ 4033965Sjdp 4133965Sjdpimport java.net.*; 4233965Sjdpimport java.util.*; 43130561Sobrienimport java.io.*; 4433965Sjdpimport javax.net.ssl.*; 4533965Sjdpimport java.security.Security; 46130561Sobrienimport java.security.KeyStore; 4733965Sjdpimport java.security.KeyFactory; 4833965Sjdpimport java.security.cert.Certificate; 4933965Sjdpimport java.security.cert.CertificateFactory; 5033965Sjdpimport java.security.spec.*; 5133965Sjdpimport java.security.interfaces.*; 5233965Sjdpimport java.util.Base64; 5333965Sjdp 5433965Sjdppublic class MD2InTrustAnchor { 5533965Sjdp 56130561Sobrien /* 5733965Sjdp * ============================================================= 5833965Sjdp * Set the various variables needed for the tests, then 5933965Sjdp * specify what tests to run on each side. 6033965Sjdp */ 6133965Sjdp 6233965Sjdp /* 6333965Sjdp * Should we run the client or server in a separate thread? 6433965Sjdp * Both sides can throw exceptions, but do you have a preference 6533965Sjdp * as to which side should be the main thread. 6633965Sjdp */ 6733965Sjdp static boolean separateServerThread = false; 6833965Sjdp 6933965Sjdp /* 7033965Sjdp * Certificates and key used in the test. 7133965Sjdp */ 7233965Sjdp 7333965Sjdp // It's a trust anchor signed with MD2 hash function. 7433965Sjdp static String trustedCertStr = 7533965Sjdp "-----BEGIN CERTIFICATE-----\n" + 7633965Sjdp "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" + 7733965Sjdp "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + 7833965Sjdp "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + 7933965Sjdp "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + 8033965Sjdp "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" + 8133965Sjdp "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" + 8233965Sjdp "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" + 8333965Sjdp "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" + 8433965Sjdp "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" + 8533965Sjdp "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + 8633965Sjdp "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" + 8733965Sjdp "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" + 8833965Sjdp "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" + 8933965Sjdp "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" + 9033965Sjdp "-----END CERTIFICATE-----"; 9133965Sjdp 9233965Sjdp // The certificate issued by above trust anchor, signed with MD5 9333965Sjdp static String targetCertStr = 9433965Sjdp "-----BEGIN CERTIFICATE-----\n" + 9533965Sjdp "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + 9633965Sjdp "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + 9733965Sjdp "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" + 9833965Sjdp "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + 9933965Sjdp "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" + 10033965Sjdp "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" + 10133965Sjdp "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" + 10233965Sjdp "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" + 10333965Sjdp "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" + 10433965Sjdp "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" + 10533965Sjdp "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" + 10633965Sjdp "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" + 10733965Sjdp "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" + 10833965Sjdp "yvudOlX4BkVR0l1K\n" + 10933965Sjdp "-----END CERTIFICATE-----"; 11033965Sjdp 11133965Sjdp // Private key in the format of PKCS#8. 11233965Sjdp static String targetPrivateKey = 11333965Sjdp "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" + 11433965Sjdp "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" + 11533965Sjdp "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" + 11633965Sjdp "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" + 11733965Sjdp "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" + 11833965Sjdp "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" + 11933965Sjdp "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" + 12033965Sjdp "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" + 12133965Sjdp "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" + 12233965Sjdp "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" + 12333965Sjdp "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" + 12433965Sjdp "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" + 12533965Sjdp "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" + 12633965Sjdp "njWHoKY3axDQ8OU=\n"; 12733965Sjdp 12833965Sjdp 12933965Sjdp static char passphrase[] = "passphrase".toCharArray(); 13033965Sjdp 13133965Sjdp /* 132130561Sobrien * Is the server ready to serve? 13333965Sjdp */ 13433965Sjdp volatile static boolean serverReady = false; 13533965Sjdp 13633965Sjdp /* 13789857Sobrien * Turn on SSL debugging? 13889857Sobrien */ 13933965Sjdp static boolean debug = false; 14033965Sjdp 14133965Sjdp /* 14233965Sjdp * Define the server side of the test. 14333965Sjdp * 14460484Sobrien * If the server prematurely exits, serverReady will be set to true 14560484Sobrien * to avoid infinite hangs. 14660484Sobrien */ 14733965Sjdp void doServerSide() throws Exception { 14833965Sjdp SSLContext context = generateSSLContext(trustedCertStr, targetCertStr, 14960484Sobrien targetPrivateKey); 15033965Sjdp SSLServerSocketFactory sslssf = context.getServerSocketFactory(); 15133965Sjdp SSLServerSocket sslServerSocket = 15233965Sjdp (SSLServerSocket)sslssf.createServerSocket(serverPort); 15333965Sjdp sslServerSocket.setNeedClientAuth(true); 15433965Sjdp serverPort = sslServerSocket.getLocalPort(); 15533965Sjdp 15633965Sjdp /* 15733965Sjdp * Signal Client, we're ready for his connect. 158130561Sobrien */ 159130561Sobrien serverReady = true; 16089857Sobrien 16189857Sobrien SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); 16289857Sobrien InputStream sslIS = sslSocket.getInputStream(); 163130561Sobrien OutputStream sslOS = sslSocket.getOutputStream(); 16489857Sobrien 16589857Sobrien sslIS.read(); 16689857Sobrien sslOS.write('A'); 16789857Sobrien sslOS.flush(); 16889857Sobrien 16933965Sjdp sslSocket.close(); 17033965Sjdp } 17133965Sjdp 17233965Sjdp /* 17333965Sjdp * Define the client side of the test. 17433965Sjdp * 17533965Sjdp * If the server prematurely exits, serverReady will be set to true 17633965Sjdp * to avoid infinite hangs. 17733965Sjdp */ 17833965Sjdp void doClientSide() throws Exception { 17933965Sjdp 18033965Sjdp /* 18133965Sjdp * Wait for server to get started. 18233965Sjdp */ 18333965Sjdp while (!serverReady) { 18433965Sjdp Thread.sleep(50); 18533965Sjdp } 18689857Sobrien 18789857Sobrien SSLContext context = generateSSLContext(trustedCertStr, targetCertStr, 18889857Sobrien targetPrivateKey); 18989857Sobrien SSLSocketFactory sslsf = context.getSocketFactory(); 19089857Sobrien 19189857Sobrien SSLSocket sslSocket = 19289857Sobrien (SSLSocket)sslsf.createSocket("localhost", serverPort); 193130561Sobrien 194130561Sobrien // enable the specified TLS protocol 19533965Sjdp sslSocket.setEnabledProtocols(new String[] {tlsProtocol}); 19633965Sjdp 19733965Sjdp InputStream sslIS = sslSocket.getInputStream(); 19833965Sjdp OutputStream sslOS = sslSocket.getOutputStream(); 19933965Sjdp 20033965Sjdp sslOS.write('B'); 20133965Sjdp sslOS.flush(); 20233965Sjdp sslIS.read(); 20389857Sobrien 20489857Sobrien sslSocket.close(); 20589857Sobrien } 20689857Sobrien 20789857Sobrien /* 20889857Sobrien * ============================================================= 209130561Sobrien * The remainder is just support stuff 210130561Sobrien */ 21133965Sjdp private static String tmAlgorithm; // trust manager 21233965Sjdp private static String tlsProtocol; // trust manager 21333965Sjdp 214130561Sobrien private static void parseArguments(String[] args) { 21533965Sjdp tmAlgorithm = args[0]; 21633965Sjdp tlsProtocol = args[1]; 21789857Sobrien } 21889857Sobrien 21989857Sobrien private static SSLContext generateSSLContext(String trustedCertStr, 22089857Sobrien String keyCertStr, String keySpecStr) throws Exception { 22133965Sjdp 22233965Sjdp // generate certificate from cert string 22333965Sjdp CertificateFactory cf = CertificateFactory.getInstance("X.509"); 22489857Sobrien 22533965Sjdp // create a key store 22633965Sjdp KeyStore ks = KeyStore.getInstance("JKS"); 22733965Sjdp ks.load(null, null); 22833965Sjdp 22933965Sjdp // import the trused cert 23033965Sjdp Certificate trusedCert = null; 23133965Sjdp ByteArrayInputStream is = null; 23233965Sjdp if (trustedCertStr != null) { 23333965Sjdp is = new ByteArrayInputStream(trustedCertStr.getBytes()); 23433965Sjdp trusedCert = cf.generateCertificate(is); 23533965Sjdp is.close(); 23633965Sjdp 23733965Sjdp ks.setCertificateEntry("RSA Export Signer", trusedCert); 23833965Sjdp } 23933965Sjdp 24033965Sjdp if (keyCertStr != null) { 241130561Sobrien // generate the private key. 24233965Sjdp PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( 24333965Sjdp Base64.getMimeDecoder().decode(keySpecStr)); 244130561Sobrien KeyFactory kf = KeyFactory.getInstance("RSA"); 24533965Sjdp RSAPrivateKey priKey = 24633965Sjdp (RSAPrivateKey)kf.generatePrivate(priKeySpec); 247130561Sobrien 24833965Sjdp // generate certificate chain 24933965Sjdp is = new ByteArrayInputStream(keyCertStr.getBytes()); 250130561Sobrien Certificate keyCert = cf.generateCertificate(is); 25133965Sjdp is.close(); 25233965Sjdp 253130561Sobrien // It's not allowed to send MD2 signed certificate to peer, 25433965Sjdp // even it may be a trusted certificate. Then we will not 25533965Sjdp // place the trusted certficate in the chain. 25633965Sjdp Certificate[] chain = new Certificate[1]; 25733965Sjdp chain[0] = keyCert; 258130561Sobrien 259130561Sobrien // import the key entry. 260130561Sobrien ks.setKeyEntry("Whatever", priKey, passphrase, chain); 261130561Sobrien } 262130561Sobrien 263130561Sobrien // create SSL context 264130561Sobrien TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); 26533965Sjdp tmf.init(ks); 26633965Sjdp 26733965Sjdp SSLContext ctx = SSLContext.getInstance(tlsProtocol); 26833965Sjdp if (keyCertStr != null && !keyCertStr.isEmpty()) { 269130561Sobrien KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); 270130561Sobrien kmf.init(ks, passphrase); 271130561Sobrien 272130561Sobrien ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 273130561Sobrien ks = null; 274130561Sobrien } else { 275130561Sobrien ctx.init(null, tmf.getTrustManagers(), null); 27633965Sjdp } 27733965Sjdp 27833965Sjdp return ctx; 27933965Sjdp } 280130561Sobrien 281130561Sobrien 282130561Sobrien // use any free port by default 283130561Sobrien volatile int serverPort = 0; 284130561Sobrien 285130561Sobrien volatile Exception serverException = null; 286130561Sobrien volatile Exception clientException = null; 287130561Sobrien 28833965Sjdp public static void main(String[] args) throws Exception { 28933965Sjdp // MD5 is used in this test case, don't disable MD5 algorithm. 29033965Sjdp Security.setProperty("jdk.certpath.disabledAlgorithms", 291130561Sobrien "MD2, RSA keySize < 1024"); 29233965Sjdp Security.setProperty("jdk.tls.disabledAlgorithms", 293130561Sobrien "SSLv3, RC4, DH keySize < 768"); 29433965Sjdp 29533965Sjdp if (debug) 29633965Sjdp System.setProperty("javax.net.debug", "all"); 29733965Sjdp 29833965Sjdp /* 29933965Sjdp * Get the customized arguments. 30033965Sjdp */ 30133965Sjdp parseArguments(args); 30233965Sjdp 30333965Sjdp /* 30433965Sjdp * Start the tests. 30533965Sjdp */ 30633965Sjdp new MD2InTrustAnchor(); 30733965Sjdp } 30833965Sjdp 309130561Sobrien Thread clientThread = null; 310130561Sobrien Thread serverThread = null; 311130561Sobrien 312130561Sobrien /* 31333965Sjdp * Primary constructor, used to drive remainder of the test. 31433965Sjdp * 31533965Sjdp * Fork off the other side, then do your work. 31633965Sjdp */ 31733965Sjdp MD2InTrustAnchor() throws Exception { 31833965Sjdp try { 31933965Sjdp if (separateServerThread) { 32033965Sjdp startServer(true); 32133965Sjdp startClient(false); 32233965Sjdp } else { 32333965Sjdp startClient(true); 32433965Sjdp startServer(false); 32533965Sjdp } 32633965Sjdp } catch (Exception e) { 32733965Sjdp // swallow for now. Show later 32833965Sjdp } 32933965Sjdp 33033965Sjdp /* 33133965Sjdp * Wait for other side to close down. 33233965Sjdp */ 33333965Sjdp if (separateServerThread) { 33433965Sjdp serverThread.join(); 33533965Sjdp } else { 33633965Sjdp clientThread.join(); 33733965Sjdp } 33833965Sjdp 33933965Sjdp /* 34033965Sjdp * When we get here, the test is pretty much over. 34133965Sjdp * Which side threw the error? 34233965Sjdp */ 343130561Sobrien Exception local; 34433965Sjdp Exception remote; 34533965Sjdp String whichRemote; 34633965Sjdp 34733965Sjdp if (separateServerThread) { 34833965Sjdp remote = serverException; 34933965Sjdp local = clientException; 350130561Sobrien whichRemote = "server"; 351130561Sobrien } else { 352130561Sobrien remote = clientException; 353130561Sobrien local = serverException; 354130561Sobrien whichRemote = "client"; 35533965Sjdp } 35633965Sjdp 35733965Sjdp /* 35833965Sjdp * If both failed, return the curthread's exception, but also 35933965Sjdp * print the remote side Exception 36033965Sjdp */ 36133965Sjdp if ((local != null) && (remote != null)) { 36233965Sjdp System.out.println(whichRemote + " also threw:"); 36333965Sjdp remote.printStackTrace(); 36433965Sjdp System.out.println(); 36533965Sjdp throw local; 36633965Sjdp } 36733965Sjdp 36833965Sjdp if (remote != null) { 36933965Sjdp throw remote; 37033965Sjdp } 37133965Sjdp 37233965Sjdp if (local != null) { 37333965Sjdp throw local; 37433965Sjdp } 37533965Sjdp } 37633965Sjdp 377130561Sobrien void startServer(boolean newThread) throws Exception { 37833965Sjdp if (newThread) { 37933965Sjdp serverThread = new Thread() { 38033965Sjdp public void run() { 38133965Sjdp try { 38233965Sjdp doServerSide(); 38333965Sjdp } catch (Exception e) { 38433965Sjdp /* 38533965Sjdp * Our server thread just died. 38633965Sjdp * 38733965Sjdp * Release the client, if not active already... 38833965Sjdp */ 38933965Sjdp System.err.println("Server died..."); 39033965Sjdp serverReady = true; 39133965Sjdp serverException = e; 39233965Sjdp } 39333965Sjdp } 39433965Sjdp }; 39533965Sjdp serverThread.start(); 39633965Sjdp } else { 39733965Sjdp try { 39833965Sjdp doServerSide(); 39933965Sjdp } catch (Exception e) { 400130561Sobrien serverException = e; 401130561Sobrien } finally { 402130561Sobrien serverReady = true; 40333965Sjdp } 404130561Sobrien } 40533965Sjdp } 40633965Sjdp 40733965Sjdp void startClient(boolean newThread) throws Exception { 408130561Sobrien if (newThread) { 40933965Sjdp clientThread = new Thread() { 410130561Sobrien public void run() { 411130561Sobrien try { 412130561Sobrien doClientSide(); 413130561Sobrien } catch (Exception e) { 414130561Sobrien /* 415130561Sobrien * Our client thread just died. 41633965Sjdp */ 41733965Sjdp System.err.println("Client died..."); 41877298Sobrien clientException = e; 41933965Sjdp } 42077298Sobrien } 42177298Sobrien }; 42277298Sobrien clientThread.start(); 42333965Sjdp } else { 42477298Sobrien try { 42533965Sjdp doClientSide(); 42677298Sobrien } catch (Exception e) { 42733965Sjdp clientException = e; 42877298Sobrien } 42977298Sobrien } 43077298Sobrien } 43133965Sjdp} 43277298Sobrien