diff --git a/.hgtags b/.hgtags index 7ffd9751c7ea9e01991fa86241397dc5c68f1cab..0928f2c79832fae7d5c040f8bc119e53a6d53b8b 100644 --- a/.hgtags +++ b/.hgtags @@ -1015,6 +1015,11 @@ d32fc856e071ff49c8a4c94682caad57f6c6874f jdk8u242-b01 2b292ab0ed9af9aa8aab27b1a80daa3509a050ba jdk8u242-b02 2f564a16517d678f31a3fa7352e16702e48c417d jdk8u242-b03 8163e59959ed5462891f2b1db7bc0fa2af1de0a6 jdk8u242-b04 +b2865f7f557fcaec84445b034b2de2b27456b6c5 jdk8u242-b05 +0d27e60569f7cf85cbdb0a83436e772e9256b5b0 jdk8u242-b06 +034a65a05bfbfb06e14d3d39efa0c9f27683573a jdk8u242-b07 +c63c2923e1f99c1f350bd24b42daf885023f18b7 jdk8u242-b08 +c63c2923e1f99c1f350bd24b42daf885023f18b7 jdk8u242-ga 44c4cee50aeb94c4629e642681ff099ad9dcac12 jdk8u252-b00 4dd113d7811ea6651c1c96f9c641b8bec8e31669 jdk8u252-b01 8d39522b0f7573e69260eb3f7af360b72b27dfc3 jdk8u252-b02 diff --git a/THIRD_PARTY_README b/THIRD_PARTY_README index 3f187565673839857a8fe8bdfb44d3c140cd56c6..a9adb432a31f43a999dd7b8ae83677affe512e1b 100644 --- a/THIRD_PARTY_README +++ b/THIRD_PARTY_README @@ -1334,11 +1334,13 @@ SUCH DAMAGE. -------------------------------------------------------------------------------- -%% This notice is provided with respect to Joni v1.1.9, which may be +%% This notice is provided with respect to Joni v2.1.16, which may be included with JRE 8, JDK 8, and OpenJDK 8. --- begin of LICENSE --- +Copyright (c) 2017 JRuby Team + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/IOUtils.java b/jdk/test/lib/testlibrary/jdk/testlibrary/IOUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/macosx/native/sun/awt/CGraphicsDevice.m b/src/macosx/native/sun/awt/CGraphicsDevice.m index c04a6a3807f91fcdf59470a25b798bedbd568220..870162e9fdda2334b93f1a7893f5332fc96757a0 100644 --- a/src/macosx/native/sun/awt/CGraphicsDevice.m +++ b/src/macosx/native/sun/awt/CGraphicsDevice.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, 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 @@ -94,16 +94,18 @@ static CFMutableArrayRef getAllValidDisplayModes(jint displayID){ static CGDisplayModeRef getBestModeForParameters(CFArrayRef allModes, int w, int h, int bpp, int refrate) { CGDisplayModeRef bestGuess = NULL; CFIndex numModes = CFArrayGetCount(allModes), n; - int thisBpp = 0; + for(n = 0; n < numModes; n++ ) { CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n); if(cRef == NULL) { continue; } CFStringRef modeString = CGDisplayModeCopyPixelEncoding(cRef); - thisBpp = getBPPFromModeString(modeString); + int thisBpp = getBPPFromModeString(modeString); CFRelease(modeString); - if (thisBpp != bpp || (int)CGDisplayModeGetHeight(cRef) != h || (int)CGDisplayModeGetWidth(cRef) != w) { + int thisH = (int)CGDisplayModeGetHeight(cRef); + int thisW = (int)CGDisplayModeGetWidth(cRef); + if (thisBpp != bpp || thisH != h || thisW != w) { // One of the key parameters does not match continue; } @@ -114,11 +116,12 @@ static CGDisplayModeRef getBestModeForParameters(CFArrayRef allModes, int w, int // Refresh rate might be 0 in display mode and we ask for specific display rate // but if we do not find exact match then 0 refresh rate might be just Ok - if (CGDisplayModeGetRefreshRate(cRef) == refrate) { + int thisRefrate = (int)CGDisplayModeGetRefreshRate(cRef); + if (thisRefrate == refrate) { // Exact match return cRef; } - if (CGDisplayModeGetRefreshRate(cRef) == 0) { + if (thisRefrate == 0) { // Not exactly what was asked for, but may fit our needs if we don't find an exact match bestGuess = cRef; } diff --git a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java index a3e9909c7c0bf9430612560f62ebc816618ec621..2800f24b6e8ff08aace0c1e35d0a22759aa82d12 100644 --- a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java +++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java @@ -45,6 +45,7 @@ import java.security.cert.CertificateFactory; import java.security.cert.CertificateException; import javax.crypto.SealedObject; +import sun.misc.IOUtils; import sun.misc.ObjectInputFilter; /** @@ -73,7 +74,7 @@ public final class JceKeyStore extends KeyStoreSpi { private static final class PrivateKeyEntry { Date date; // the creation date of this entry byte[] protectedKey; - Certificate chain[]; + Certificate[] chain; }; // Secret key @@ -742,23 +743,11 @@ public final class JceKeyStore extends KeyStoreSpi { entry.date = new Date(dis.readLong()); // read the private key - try { - entry.protectedKey = new byte[dis.readInt()]; - } catch (OutOfMemoryError e) { - throw new IOException("Keysize too big"); - } - dis.readFully(entry.protectedKey); + entry.protectedKey = IOUtils.readExactlyNBytes(dis, dis.readInt()); // read the certificate chain int numOfCerts = dis.readInt(); - try { - if (numOfCerts > 0) { - entry.chain = new Certificate[numOfCerts]; - } - } catch (OutOfMemoryError e) { - throw new IOException("Too many certificates in " - + "chain"); - } + List tmpCerts = new ArrayList<>(); for (int j = 0; j < numOfCerts; j++) { if (xVersion == 2) { // read the certificate type, and instantiate a @@ -766,27 +755,24 @@ public final class JceKeyStore extends KeyStoreSpi { // existing factory if possible) String certType = dis.readUTF(); if (cfs.containsKey(certType)) { - // reuse certificate factory + // reuse certificate factory cf = cfs.get(certType); } else { - // create new certificate factory + // create new certificate factory cf = CertificateFactory.getInstance( certType); - // store the certificate factory so we can - // reuse it later + // store the certificate factory so we can + // reuse it later cfs.put(certType, cf); } } // instantiate the certificate - try { - encoded = new byte[dis.readInt()]; - } catch (OutOfMemoryError e) { - throw new IOException("Certificate too big"); - } - dis.readFully(encoded); + encoded = IOUtils.readExactlyNBytes(dis, dis.readInt()); bais = new ByteArrayInputStream(encoded); - entry.chain[j] = cf.generateCertificate(bais); + tmpCerts.add(cf.generateCertificate(bais)); } + entry.chain = tmpCerts.toArray( + new Certificate[numOfCerts]); // Add the entry to the list entries.put(alias, entry); @@ -818,12 +804,7 @@ public final class JceKeyStore extends KeyStoreSpi { cfs.put(certType, cf); } } - try { - encoded = new byte[dis.readInt()]; - } catch (OutOfMemoryError e) { - throw new IOException("Certificate too big"); - } - dis.readFully(encoded); + encoded = IOUtils.readExactlyNBytes(dis, dis.readInt()); bais = new ByteArrayInputStream(encoded); entry.cert = cf.generateCertificate(bais); @@ -882,18 +863,14 @@ public final class JceKeyStore extends KeyStoreSpi { * with */ if (password != null) { - byte computed[], actual[]; - computed = md.digest(); - actual = new byte[computed.length]; - dis.readFully(actual); - for (int i = 0; i < computed.length; i++) { - if (computed[i] != actual[i]) { - throw new IOException( + byte[] computed = md.digest(); + byte[] actual = IOUtils.readExactlyNBytes(dis, computed.length); + if (!MessageDigest.isEqual(computed, actual)) { + throw new IOException( "Keystore was tampered with, or " + "password was incorrect", - new UnrecoverableKeyException( - "Password verification failed")); - } + new UnrecoverableKeyException( + "Password verification failed")); } } } finally { diff --git a/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java b/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java index 3da159f6e29033716cd7a5a48ecbfcb2a64b818c..e86e60ea82183c98799e467fa5f0b18515b1c4ff 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java +++ b/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java @@ -123,6 +123,13 @@ class ClassReader { return e; } + private Entry checkValid(Entry e) { + if (e == INVALID_ENTRY) { + throw new IllegalStateException("Invalid constant pool reference"); + } + return e; + } + /** Throw a ClassFormatException if the entry does not match the expected tag type. */ private Entry checkTag(Entry e, byte tag) throws ClassFormatException { if (e == null || !e.tagMatches(tag)) { @@ -225,6 +232,29 @@ class ClassReader { return null; // OK } + // use this identity for invalid references + private static final Entry INVALID_ENTRY = new Entry((byte) -1) { + @Override + public boolean equals(Object o) { + throw new IllegalStateException("Should not call this"); + } + + @Override + protected int computeValueHash() { + throw new IllegalStateException("Should not call this"); + } + + @Override + public int compareTo(Object o) { + throw new IllegalStateException("Should not call this"); + } + + @Override + public String stringValue() { + throw new IllegalStateException("Should not call this"); + } + }; + void readConstantPool() throws IOException { int length = in.readUnsignedShort(); //System.err.println("reading CP, length="+length); @@ -233,7 +263,7 @@ class ClassReader { int fptr = 0; Entry[] cpMap = new Entry[length]; - cpMap[0] = null; + cpMap[0] = INVALID_ENTRY; for (int i = 1; i < length; i++) { //System.err.println("reading CP elt, i="+i); int tag = in.readByte(); @@ -254,13 +284,13 @@ class ClassReader { case CONSTANT_Long: { cpMap[i] = ConstantPool.getLiteralEntry(in.readLong()); - cpMap[++i] = null; + cpMap[++i] = INVALID_ENTRY; } break; case CONSTANT_Double: { cpMap[i] = ConstantPool.getLiteralEntry(in.readDouble()); - cpMap[++i] = null; + cpMap[++i] = INVALID_ENTRY; } break; @@ -315,7 +345,7 @@ class ClassReader { int ref2 = fixups[fi++]; if (verbose > 3) Utils.log.fine(" cp["+cpi+"] = "+ConstantPool.tagName(tag)+"{"+ref+","+ref2+"}"); - if (ref >= 0 && cpMap[ref] == null || ref2 >= 0 && cpMap[ref2] == null) { + if (ref >= 0 && checkValid(cpMap[ref]) == null || ref2 >= 0 && checkValid(cpMap[ref2]) == null) { // Defer. fixups[fptr++] = cpi; fixups[fptr++] = tag; @@ -364,7 +394,6 @@ class ClassReader { cls.cpMap = cpMap; } - private /*non-static*/ class UnresolvedEntry extends Entry { final Object[] refsOrIndexes; diff --git a/src/share/classes/com/sun/jndi/ldap/Connection.java b/src/share/classes/com/sun/jndi/ldap/Connection.java index 43e83c12b50782754ba18b43c05b74da300a8b69..e36670e34c6eaa638e5e3be35c82d64de34f83ae 100644 --- a/src/share/classes/com/sun/jndi/ldap/Connection.java +++ b/src/share/classes/com/sun/jndi/ldap/Connection.java @@ -47,8 +47,6 @@ import javax.naming.ldap.Control; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; -import sun.misc.IOUtils; - /** * A thread that creates a connection to an LDAP server. * After the connection, the thread reads from the connection. @@ -886,7 +884,7 @@ public final class Connection implements Runnable { } // read in seqlen bytes - byte[] left = IOUtils.readFully(in, seqlen, false); + byte[] left = readFully(in, seqlen); inbuf = Arrays.copyOf(inbuf, offset + left.length); System.arraycopy(left, 0, inbuf, offset, left.length); offset += left.length; @@ -981,6 +979,31 @@ System.err.println("bytesread: " + bytesread); } } + private static byte[] readFully(InputStream is, int length) + throws IOException + { + byte[] buf = new byte[Math.min(length, 8192)]; + int nread = 0; + while (nread < length) { + int bytesToRead; + if (nread >= buf.length) { // need to allocate a larger buffer + bytesToRead = Math.min(length - nread, buf.length + 8192); + if (buf.length < nread + bytesToRead) { + buf = Arrays.copyOf(buf, nread + bytesToRead); + } + } else { + bytesToRead = buf.length - nread; + } + int count = is.read(buf, nread, bytesToRead); + if (count < 0) { + if (buf.length != nread) + buf = Arrays.copyOf(buf, nread); + break; + } + nread += count; + } + return buf; + } // This code must be uncommented to run the LdapAbandonTest. /*public void sendSearchReqs(String dn, int numReqs) { diff --git a/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 8547363b183536b029458f32063df16b5a96afbe..448764cc9f833f4691719b0f3e5dba417fa1f2a6 100644 --- a/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -123,8 +123,9 @@ import sun.misc.HexDumpEncoder; * must also be set to true; Otherwise a configuration error will * be returned. *
renewTGT:
- *
Set this to true, if you want to renew - * the TGT. If this is set, useTicketCache must also be + *
Set this to true, if you want to renew the TGT when it's more than + * half-way expired (the time until expiration is less than the time + * since start time). If this is set, {@code useTicketCache} must also be * set to true; otherwise a configuration error will be returned.
*
doNotPrompt:
*
Set this to true if you do not want to be @@ -665,22 +666,21 @@ public class Krb5LoginModule implements LoginModule { (principal, ticketCacheName); if (cred != null) { - // check to renew credentials - if (!isCurrent(cred)) { - if (renewTGT) { - Credentials newCred = renewCredentials(cred); - if (newCred != null) { - newCred.setProxy(cred.getProxy()); - } + if (renewTGT && isOld(cred)) { + // renew if ticket is old. + Credentials newCred = renewCredentials(cred); + if (newCred != null) { + newCred.setProxy(cred.getProxy()); cred = newCred; - } else { - // credentials have expired - cred = null; - if (debug) - System.out.println("Credentials are" + - " no longer valid"); } } + if (!isCurrent(cred)) { + // credentials have expired + cred = null; + if (debug) + System.out.println("Credentials are" + + " no longer valid"); + } } if (cred != null) { @@ -988,7 +988,7 @@ public class Krb5LoginModule implements LoginModule { } } - private boolean isCurrent(Credentials creds) + private static boolean isCurrent(Credentials creds) { Date endTime = creds.getEndTime(); if (endTime != null) { @@ -997,6 +997,23 @@ public class Krb5LoginModule implements LoginModule { return true; } + private static boolean isOld(Credentials creds) + { + Date endTime = creds.getEndTime(); + if (endTime != null) { + Date authTime = creds.getAuthTime(); + long now = System.currentTimeMillis(); + if (authTime != null) { + // pass the mid between auth and end + return now - authTime.getTime() > endTime.getTime() - now; + } else { + // will expire in less than 2 hours + return now <= endTime.getTime() - 1000*3600*2L; + } + } + return false; + } + private Credentials renewCredentials(Credentials creds) { Credentials lcreds; @@ -1004,6 +1021,10 @@ public class Krb5LoginModule implements LoginModule { if (!creds.isRenewable()) throw new RefreshFailedException("This ticket" + " is not renewable"); + if (creds.getRenewTill() == null) { + // Renewable ticket without renew-till. Illegal and ignored. + return creds; + } if (System.currentTimeMillis() > cred.getRenewTill().getTime()) throw new RefreshFailedException("This ticket is past " + "its last renewal time."); diff --git a/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java b/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java index 30461e25f7c8d94103cdcf5abf4c60261f7233f1..baa836efe5cfe7fa9356a0c1472b71ab84f5447a 100644 --- a/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java +++ b/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -73,8 +73,12 @@ abstract class GssKrb5Base extends AbstractSaslImpl { } try { - MessageProp msgProp = new MessageProp(JGSS_QOP, privacy); + MessageProp msgProp = new MessageProp(JGSS_QOP, false); byte[] answer = secCtx.unwrap(incoming, start, len, msgProp); + if (privacy && !msgProp.getPrivacy()) { + throw new SaslException("Privacy not protected"); + } + checkMessageProp("", msgProp); if (logger.isLoggable(Level.FINEST)) { traceOutput(myClassName, "KRB501:Unwrap", "incoming: ", incoming, start, len); @@ -128,4 +132,20 @@ abstract class GssKrb5Base extends AbstractSaslImpl { protected void finalize() throws Throwable { dispose(); } + + void checkMessageProp(String label, MessageProp msgProp) + throws SaslException { + if (msgProp.isDuplicateToken()) { + throw new SaslException(label + "Duplicate token"); + } + if (msgProp.isGapToken()) { + throw new SaslException(label + "Gap token"); + } + if (msgProp.isOldToken()) { + throw new SaslException(label + "Old token"); + } + if (msgProp.isUnseqToken()) { + throw new SaslException(label + "Token not in sequence"); + } + } } diff --git a/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java b/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java index e8d9a4cc866c0b6b80a44a1d270bb871e70455bd..34a879ab65690e637f0e94259963866973688f8d 100644 --- a/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java +++ b/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -230,8 +230,10 @@ final class GssKrb5Client extends GssKrb5Base implements SaslClient { // Received S1 (security layer, server max recv size) + MessageProp msgProp = new MessageProp(false); byte[] gssOutToken = secCtx.unwrap(challengeData, 0, - challengeData.length, new MessageProp(0, false)); + challengeData.length, msgProp); + checkMessageProp("Handshake failure: ", msgProp); // First octet is a bit-mask specifying the protections // supported by the server diff --git a/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java b/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java index 94ce39c0ad14281264933e582fbc5a465bcfdc14..10c429aca575f819b20899c0ed0bc9f451e4c2cd 100644 --- a/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java +++ b/src/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -250,8 +250,10 @@ final class GssKrb5Server extends GssKrb5Base implements SaslServer { try { // Expecting 4 octets from client selected protection // and client's receive buffer size + MessageProp msgProp = new MessageProp(false); byte[] gssOutToken = secCtx.unwrap(responseData, 0, - responseData.length, new MessageProp(0, false)); + responseData.length, msgProp); + checkMessageProp("Handshake failure: ", msgProp); if (logger.isLoggable(Level.FINER)) { traceOutput(MY_CLASS_NAME, "doHandshake2", diff --git a/src/share/classes/java/awt/color/ICC_Profile.java b/src/share/classes/java/awt/color/ICC_Profile.java index 89abeca03d65e0758989facbad0e7f617903d603..af1e5fc700c9642a19b02c2805b30498b19a876c 100644 --- a/src/share/classes/java/awt/color/ICC_Profile.java +++ b/src/share/classes/java/awt/color/ICC_Profile.java @@ -43,7 +43,9 @@ import sun.java2d.cmm.ProfileDataVerifier; import sun.java2d.cmm.ProfileDeferralMgr; import sun.java2d.cmm.ProfileDeferralInfo; import sun.java2d.cmm.ProfileActivator; +import sun.misc.IOUtils; +import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -1019,42 +1021,25 @@ public class ICC_Profile implements Serializable { static byte[] getProfileDataFromStream(InputStream s) throws IOException { - byte profileData[]; - int profileSize; - byte header[] = new byte[128]; - int bytestoread = 128; - int bytesread = 0; - int n; + BufferedInputStream bis = new BufferedInputStream(s); + bis.mark(128); - while (bytestoread != 0) { - if ((n = s.read(header, bytesread, bytestoread)) < 0) { - return null; - } - bytesread += n; - bytestoread -= n; - } + byte[] header = IOUtils.readNBytes(bis, 128); if (header[36] != 0x61 || header[37] != 0x63 || header[38] != 0x73 || header[39] != 0x70) { return null; /* not a valid profile */ } - profileSize = ((header[0] & 0xff) << 24) | - ((header[1] & 0xff) << 16) | - ((header[2] & 0xff) << 8) | - (header[3] & 0xff); - profileData = new byte[profileSize]; - System.arraycopy(header, 0, profileData, 0, 128); - bytestoread = profileSize - 128; - bytesread = 128; - while (bytestoread != 0) { - if ((n = s.read(profileData, bytesread, bytestoread)) < 0) { - return null; - } - bytesread += n; - bytestoread -= n; + int profileSize = ((header[0] & 0xff) << 24) | + ((header[1] & 0xff) << 16) | + ((header[2] & 0xff) << 8) | + (header[3] & 0xff); + bis.reset(); + try { + return IOUtils.readNBytes(bis, profileSize); + } catch (OutOfMemoryError e) { + throw new IOException("Color profile is too big"); } - - return profileData; } diff --git a/src/share/classes/java/beans/beancontext/BeanContextSupport.java b/src/share/classes/java/beans/beancontext/BeanContextSupport.java index 43dfcb02c977c3640c9864e43a6ca89c1d98f81c..9ce1658de2f371803a0a5eadf1d969d77e488a11 100644 --- a/src/share/classes/java/beans/beancontext/BeanContextSupport.java +++ b/src/share/classes/java/beans/beancontext/BeanContextSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, 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 @@ -1024,18 +1024,8 @@ public class BeanContextSupport extends BeanContextChildSupport int count = serializable; while (count-- > 0) { - Object child = null; - BeanContextSupport.BCSChild bscc = null; - - try { - child = ois.readObject(); - bscc = (BeanContextSupport.BCSChild)ois.readObject(); - } catch (IOException ioe) { - continue; - } catch (ClassNotFoundException cnfe) { - continue; - } - + Object child = ois.readObject(); + BCSChild bscc = (BCSChild) ois.readObject(); synchronized(child) { BeanContextChild bcc = null; diff --git a/src/share/classes/java/io/FilePermission.java b/src/share/classes/java/io/FilePermission.java index 3e0f7d871ce1b39a1e5b1e15a2d740f85243d086..ae4a9194d61d7cc856b02c4a17d9be11c2e497d0 100644 --- a/src/share/classes/java/io/FilePermission.java +++ b/src/share/classes/java/io/FilePermission.java @@ -46,8 +46,11 @@ import sun.security.util.SecurityConstants; * the file separator character, File.separatorChar) indicates * all the files and directories contained in that directory. A pathname * that ends with "/-" indicates (recursively) all files - * and subdirectories contained in that directory. A pathname consisting of - * the special token "<<ALL FILES>>" matches any file. + * and subdirectories contained in that directory. Such a pathname is called + * a wildcard pathname. Otherwise, it's a simple pathname. + *

+ * A pathname consisting of the special token {@literal "<>"} + * matches any file. *

* Note: A pathname consisting of a single "*" indicates all the files * in the current directory, while a pathname consisting of a single "-" @@ -80,7 +83,7 @@ import sun.security.util.SecurityConstants; *

* Be careful when granting FilePermissions. Think about the implications * of granting read and especially write access to various files and - * directories. The "<<ALL FILES>>" permission with write action is + * directories. The {@literal "<>"} permission with write action is * especially dangerous. This grants permission to write to the entire * file system. One thing this effectively allows is replacement of the * system binary, including the JVM runtime environment. @@ -156,6 +159,7 @@ public final class FilePermission extends Permission implements Serializable { private transient String cpath; + private transient boolean allFiles; // whether this is <> private transient boolean invalid; // whether input path is invalid // static Strings used by init(int mask) @@ -207,6 +211,7 @@ public final class FilePermission extends Permission implements Serializable { this.mask = mask; if (cpath.equals("<>")) { + allFiles = true; directory = true; recursive = true; cpath = ""; @@ -335,6 +340,23 @@ public final class FilePermission extends Permission implements Serializable { * "/tmp/*" encompasses all files in the "/tmp" directory, * including the one named "foo". * + *

+ * Precisely, a simple pathname implies another simple pathname + * if and only if they are equal. A simple pathname never implies + * a wildcard pathname. A wildcard pathname implies another wildcard + * pathname if and only if all simple pathnames implied by the latter + * are implied by the former. A wildcard pathname implies a simple + * pathname if and only if + *

+ *

+ * {@literal "<>"} implies every other pathname. No pathname, + * except for {@literal "<>"} itself, implies + * {@literal "<>"}. * * @param p the permission to check against. * @@ -366,9 +388,15 @@ public final class FilePermission extends Permission implements Serializable { if (this == that) { return true; } + if (allFiles) { + return true; + } if (this.invalid || that.invalid) { return false; } + if (that.allFiles) { + return false; + } if (this.directory) { if (this.recursive) { // make sure that.path is longer then path so @@ -415,6 +443,10 @@ public final class FilePermission extends Permission implements Serializable { * Checks two FilePermission objects for equality. Checks that obj is * a FilePermission, and has the same pathname and actions as this object. * + * @implNote More specifically, two pathnames are the same if and only if + * they have the same wildcard flag and their + * {@code npath} are equal. Or they are both {@literal "<>"}. + * * @param obj the object we are testing for equality with this object. * @return true if obj is a FilePermission, and has the same * pathname and actions as this FilePermission object, @@ -433,6 +465,7 @@ public final class FilePermission extends Permission implements Serializable { return false; } return (this.mask == that.mask) && + (this.allFiles == that.allFiles) && this.cpath.equals(that.cpath) && (this.directory == that.directory) && (this.recursive == that.recursive); diff --git a/src/share/classes/java/io/ObjectInputStream.java b/src/share/classes/java/io/ObjectInputStream.java index 9d293c707c192018a180a4e0e61fe50598f0c0d9..b16d53b4bc64628abb800be3ae28621b907e414a 100644 --- a/src/share/classes/java/io/ObjectInputStream.java +++ b/src/share/classes/java/io/ObjectInputStream.java @@ -419,16 +419,50 @@ public class ObjectInputStream * @throws IOException Any of the usual Input/Output related exceptions. */ public final Object readObject() + throws IOException, ClassNotFoundException { + return readObject(Object.class); + } + + /** + * Reads a String and only a string. + * + * @return the String read + * @throws EOFException If end of file is reached. + * @throws IOException If other I/O error has occurred. + */ + private String readString() throws IOException { + try { + return (String) readObject(String.class); + } catch (ClassNotFoundException cnf) { + throw new IllegalStateException(cnf); + } + } + + /** + * Internal method to read an object from the ObjectInputStream of the expected type. + * Called only from {@code readObject()} and {@code readString()}. + * Only {@code Object.class} and {@code String.class} are supported. + * + * @param type the type expected; either Object.class or String.class + * @return an object of the type + * @throws IOException Any of the usual Input/Output related exceptions. + * @throws ClassNotFoundException Class of a serialized object cannot be + * found. + */ + private final Object readObject(Class type) throws IOException, ClassNotFoundException { if (enableOverride) { return readObjectOverride(); } + if (! (type == Object.class || type == String.class)) + throw new AssertionError("internal error"); + // if nested read, passHandle contains handle of enclosing object int outerHandle = passHandle; try { - Object obj = readObject0(false); + Object obj = readObject0(type, false); handles.markDependency(outerHandle, passHandle); ClassNotFoundException ex = handles.lookupException(passHandle); if (ex != null) { @@ -518,7 +552,7 @@ public class ObjectInputStream // if nested read, passHandle contains handle of enclosing object int outerHandle = passHandle; try { - Object obj = readObject0(true); + Object obj = readObject0(Object.class, true); handles.markDependency(outerHandle, passHandle); ClassNotFoundException ex = handles.lookupException(passHandle); if (ex != null) { @@ -1517,8 +1551,10 @@ public class ObjectInputStream /** * Underlying readObject implementation. + * @param type a type expected to be deserialized; non-null + * @param unshared true if the object can not be a reference to a shared object, otherwise false */ - private Object readObject0(boolean unshared) throws IOException { + private Object readObject0(Class type, boolean unshared) throws IOException { boolean oldMode = bin.getBlockDataMode(); if (oldMode) { int remain = bin.currentBlockRemaining(); @@ -1550,13 +1586,20 @@ public class ObjectInputStream return readNull(); case TC_REFERENCE: - return readHandle(unshared); + // check the type of the existing object + return type.cast(readHandle(unshared)); case TC_CLASS: + if (type == String.class) { + throw new ClassCastException("Cannot cast a class to java.lang.String"); + } return readClass(unshared); case TC_CLASSDESC: case TC_PROXYCLASSDESC: + if (type == String.class) { + throw new ClassCastException("Cannot cast a class to java.lang.String"); + } return readClassDesc(unshared); case TC_STRING: @@ -1564,15 +1607,27 @@ public class ObjectInputStream return checkResolve(readString(unshared)); case TC_ARRAY: + if (type == String.class) { + throw new ClassCastException("Cannot cast an array to java.lang.String"); + } return checkResolve(readArray(unshared)); case TC_ENUM: + if (type == String.class) { + throw new ClassCastException("Cannot cast an enum to java.lang.String"); + } return checkResolve(readEnum(unshared)); case TC_OBJECT: + if (type == String.class) { + throw new ClassCastException("Cannot cast an object to java.lang.String"); + } return checkResolve(readOrdinaryObject(unshared)); case TC_EXCEPTION: + if (type == String.class) { + throw new ClassCastException("Cannot cast an exception to java.lang.String"); + } IOException ex = readFatalException(); throw new WriteAbortedException("writing aborted", ex); @@ -1947,7 +2002,7 @@ public class ObjectInputStream if (ccl == null) { for (int i = 0; i < len; i++) { - readObject0(false); + readObject0(Object.class, false); } } else if (ccl.isPrimitive()) { if (ccl == Integer.TYPE) { @@ -1972,7 +2027,7 @@ public class ObjectInputStream } else { Object[] oa = (Object[]) array; for (int i = 0; i < len; i++) { - oa[i] = readObject0(false); + oa[i] = readObject0(Object.class, false); handles.markDependency(arrayHandle, passHandle); } } @@ -2250,7 +2305,7 @@ public class ObjectInputStream return; default: - readObject0(false); + readObject0(Object.class, false); break; } } @@ -2284,7 +2339,7 @@ public class ObjectInputStream int numPrimFields = fields.length - objVals.length; for (int i = 0; i < objVals.length; i++) { ObjectStreamField f = fields[numPrimFields + i]; - objVals[i] = readObject0(f.isUnshared()); + objVals[i] = readObject0(Object.class, f.isUnshared()); if (f.getField() != null) { handles.markDependency(objHandle, passHandle); } @@ -2305,7 +2360,7 @@ public class ObjectInputStream throw new InternalError(); } clear(); - return (IOException) readObject0(false); + return (IOException) readObject0(Object.class, false); } /** @@ -2449,7 +2504,7 @@ public class ObjectInputStream int numPrimFields = fields.length - objVals.length; for (int i = 0; i < objVals.length; i++) { objVals[i] = - readObject0(fields[numPrimFields + i].isUnshared()); + readObject0(Object.class, fields[numPrimFields + i].isUnshared()); objHandles[i] = passHandle; } passHandle = oldHandle; @@ -3403,7 +3458,15 @@ public class ObjectInputStream * utflen bytes. */ private String readUTFBody(long utflen) throws IOException { - StringBuilder sbuf = new StringBuilder(); + StringBuilder sbuf; + if (utflen > 0 && utflen < Integer.MAX_VALUE) { + // a reasonable initial capacity based on the UTF length + int initialCapacity = Math.min((int)utflen, 0xFFFF); + sbuf = new StringBuilder(initialCapacity); + } else { + sbuf = new StringBuilder(); + } + if (!blkmode) { end = pos = 0; } @@ -3918,5 +3981,6 @@ public class ObjectInputStream } static { SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::setValidator); + SharedSecrets.setJavaObjectInputStreamReadString(ObjectInputStream::readString); } } diff --git a/src/share/classes/java/lang/ClassLoader.java b/src/share/classes/java/lang/ClassLoader.java index 2e98092f63e97df487d28b768df506d957d6eb9d..925fdacce3fd969eb45ac9b9b5ff82fd69487885 100644 --- a/src/share/classes/java/lang/ClassLoader.java +++ b/src/share/classes/java/lang/ClassLoader.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Azul Systems, Inc. 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 @@ -1467,6 +1468,17 @@ public abstract class ClassLoader { } } + /* + * Initialize default paths for native libraries search. + * Must be done early as JDK may load libraries during bootstrap. + * + * @see java.lang.System#initPhase1 + */ + static void initLibraryPaths() { + usr_paths = initializePath("java.library.path"); + sys_paths = initializePath("sun.boot.library.path"); + } + // Returns true if the specified class loader can be found in this class // loader's delegation chain. boolean isAncestor(ClassLoader cl) { @@ -1809,10 +1821,9 @@ public abstract class ClassLoader { boolean isAbsolute) { ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader(); - if (sys_paths == null) { - usr_paths = initializePath("java.library.path"); - sys_paths = initializePath("sun.boot.library.path"); - } + assert sys_paths != null : "should be initialized at this point"; + assert usr_paths != null : "should be initialized at this point"; + if (isAbsolute) { if (loadLibrary0(fromClass, new File(name))) { return; @@ -1902,13 +1913,14 @@ public abstract class ClassLoader { name + " already loaded in another classloader"); } - /* If the library is being loaded (must be by the same thread, - * because Runtime.load and Runtime.loadLibrary are - * synchronous). The reason is can occur is that the JNI_OnLoad - * function can cause another loadLibrary invocation. + /* + * When a library is being loaded, JNI_OnLoad function can cause + * another loadLibrary invocation that should succeed. * - * Thus we can use a static stack to hold the list of libraries - * we are loading. + * We use a static stack to hold the list of libraries we are + * loading because this can happen only when called by the + * same thread because Runtime.load and Runtime.loadLibrary + * are synchronous. * * If there is a pending load operation for the library, we * immediately return success; otherwise, we raise diff --git a/src/share/classes/java/lang/Runtime.java b/src/share/classes/java/lang/Runtime.java index 9e53dc939ecbe93804ba6d42eedbefff7f2835d9..5039059149f102f9e2390fe17731a76244478a26 100644 --- a/src/share/classes/java/lang/Runtime.java +++ b/src/share/classes/java/lang/Runtime.java @@ -1,5 +1,6 @@ /* * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Azul Systems, Inc. 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 @@ -797,7 +798,7 @@ public class Runtime { load0(Reflection.getCallerClass(), filename); } - synchronized void load0(Class fromClass, String filename) { + void load0(Class fromClass, String filename) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkLink(filename); @@ -858,14 +859,14 @@ public class Runtime { loadLibrary0(Reflection.getCallerClass(), libname); } - synchronized void loadLibrary0(Class fromClass, String libname) { + void loadLibrary0(Class fromClass, String libname) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkLink(libname); } if (libname.indexOf((int)File.separatorChar) != -1) { throw new UnsatisfiedLinkError( - "Directory separator should not appear in library name: " + libname); + "Directory separator should not appear in library name: " + libname); } ClassLoader.loadLibrary(fromClass, libname, false); } diff --git a/src/share/classes/java/lang/System.java b/src/share/classes/java/lang/System.java index b2747fa7a41bc60266d3811b04fe371e97baa35c..c568f02ee662f90f65aa3a8a56264e49a6b8ccf9 100644 --- a/src/share/classes/java/lang/System.java +++ b/src/share/classes/java/lang/System.java @@ -43,6 +43,8 @@ import sun.reflect.Reflection; import sun.security.util.SecurityConstants; import sun.reflect.annotation.AnnotationType; +import jdk.internal.util.StaticProperty; + /** * The System class contains several useful class fields * and methods. It cannot be instantiated. @@ -1183,6 +1185,7 @@ public final class System { lineSeparator = props.getProperty("line.separator"); + StaticProperty.jdkSerialFilter(); // Load StaticProperty to cache the property values sun.misc.Version.init(); FileInputStream fdIn = new FileInputStream(FileDescriptor.in); @@ -1192,6 +1195,8 @@ public final class System { setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding"))); setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding"))); + ClassLoader.initLibraryPaths(); + // Load the zip library now in order to keep java.util.zip.ZipFile // from trying to use itself to load this library later. loadLibrary("zip"); diff --git a/src/share/classes/java/net/URL.java b/src/share/classes/java/net/URL.java index bbe87b62722cc6e6899f18bfaa36545dd4c97df1..820733ca2ef61932069aed3cb91c3b01917087cf 100644 --- a/src/share/classes/java/net/URL.java +++ b/src/share/classes/java/net/URL.java @@ -33,6 +33,7 @@ import java.io.ObjectStreamField; import java.io.ObjectInputStream.GetField; import java.util.Hashtable; import java.util.StringTokenizer; +import sun.misc.VM; import sun.net.util.IPAddressUtil; import sun.security.util.SecurityConstants; @@ -1423,7 +1424,9 @@ public final class URL implements java.io.Serializable { } boolean isBuiltinStreamHandler(URLStreamHandler handler) { - return isBuiltinStreamHandler(handler.getClass().getName()); + Class handlerClass = handler.getClass(); + return isBuiltinStreamHandler(handlerClass.getName()) + || VM.isSystemDomainLoader(handlerClass.getClassLoader()); } private boolean isBuiltinStreamHandler(String handlerClassName) { diff --git a/src/share/classes/java/nio/channels/SelectableChannel.java b/src/share/classes/java/nio/channels/SelectableChannel.java index 997d5c5ec57dbd6c1272f0cff3f16d520ee3e6e7..c7d75967aa841c3616ee5b57acd4b749c3be18eb 100644 --- a/src/share/classes/java/nio/channels/SelectableChannel.java +++ b/src/share/classes/java/nio/channels/SelectableChannel.java @@ -121,7 +121,7 @@ public abstract class SelectableChannel // keySet, may be empty but is never null, typ. a tiny array // boolean isRegistered, protected by key set // regLock, lock object to prevent duplicate registrations - // boolean isBlocking, protected by regLock + // blocking mode, protected by regLock /** * Tells whether or not this channel is currently registered with any diff --git a/src/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java b/src/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java index 0de212d2df479f58c8b53760ee50957ea8ce1022..d5b3ce8bba32862080e007478edb534eb7ff7a5a 100644 --- a/src/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java +++ b/src/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -26,7 +26,14 @@ package java.nio.channels.spi; import java.io.IOException; -import java.nio.channels.*; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.IllegalSelectorException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; /** @@ -67,8 +74,8 @@ public abstract class AbstractSelectableChannel // Lock for registration and configureBlocking operations private final Object regLock = new Object(); - // Blocking mode, protected by regLock - boolean blocking = true; + // True when non-blocking, need regLock to change; + private volatile boolean nonBlocking; /** * Initializes a new instance of this class. @@ -197,7 +204,7 @@ public abstract class AbstractSelectableChannel throw new ClosedChannelException(); if ((ops & ~validOps()) != 0) throw new IllegalArgumentException(); - if (blocking) + if (isBlocking()) throw new IllegalBlockingModeException(); SelectionKey k = findKey(sel); if (k != null) { @@ -264,9 +271,7 @@ public abstract class AbstractSelectableChannel // -- Blocking -- public final boolean isBlocking() { - synchronized (regLock) { - return blocking; - } + return !nonBlocking; } public final Object blockingLock() { @@ -287,12 +292,13 @@ public abstract class AbstractSelectableChannel synchronized (regLock) { if (!isOpen()) throw new ClosedChannelException(); - if (blocking == block) - return this; - if (block && haveValidKeys()) - throw new IllegalBlockingModeException(); - implConfigureBlocking(block); - blocking = block; + boolean blocking = !nonBlocking; + if (block != blocking) { + if (block && haveValidKeys()) + throw new IllegalBlockingModeException(); + implConfigureBlocking(block); + nonBlocking = !block; + } } return this; } diff --git a/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java b/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java index c17eac6cfe82cdced876e016f2a016bc761b98ea..3482b274c6bd0cfec1766aad2a1c610c8de8549d 100644 --- a/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java +++ b/src/share/classes/java/rmi/server/RemoteObjectInvocationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -29,6 +29,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.rmi.Remote; +import java.rmi.RemoteException; import java.rmi.UnexpectedException; import java.rmi.activation.Activatable; import java.security.PrivilegedAction; @@ -224,6 +225,13 @@ public class RemoteObjectInvocationHandler throw new IllegalArgumentException( "proxy not Remote instance"); } + + // Verify that the method is declared on an interface that extends Remote + Class decl = method.getDeclaringClass(); + if (!Remote.class.isAssignableFrom(decl)) { + throw new RemoteException("Method is not Remote: " + decl + "::" + method); + } + return ref.invoke((Remote) proxy, method, args, getMethodHash(method)); } catch (Exception e) { diff --git a/src/share/classes/java/security/CodeSource.java b/src/share/classes/java/security/CodeSource.java index eb78c1d7a2209834a973733051f56433c9fdcaba..e2ca471360ad9f5826c5a668a1fac71e32561128 100644 --- a/src/share/classes/java/security/CodeSource.java +++ b/src/share/classes/java/security/CodeSource.java @@ -570,7 +570,7 @@ public class CodeSource implements java.io.Serializable { cfs.put(certType, cf); } // parse the certificate - byte[] encoded = IOUtils.readNBytes(ois, ois.readInt()); + byte[] encoded = IOUtils.readExactlyNBytes(ois, ois.readInt()); ByteArrayInputStream bais = new ByteArrayInputStream(encoded); try { certList.add(cf.generateCertificate(bais)); diff --git a/src/share/classes/java/security/Key.java b/src/share/classes/java/security/Key.java index c0c63d7c7c10630943d3d608d160382aabf1de12..09542e394a25f3722aa4a43701ef8e17b28a14c4 100644 --- a/src/share/classes/java/security/Key.java +++ b/src/share/classes/java/security/Key.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, 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 @@ -63,7 +63,7 @@ package java.security; * * * For more information, see - * RFC 3280: + * RFC 5280: * Internet X.509 Public Key Infrastructure Certificate and CRL Profile. * *

  • A Format diff --git a/src/share/classes/java/security/UnresolvedPermission.java b/src/share/classes/java/security/UnresolvedPermission.java index 2e8f5c755a3ccdc98520616aed221703493724a7..c7eee55af7c4cdbc40afef50d487d205477fa3ab 100644 --- a/src/share/classes/java/security/UnresolvedPermission.java +++ b/src/share/classes/java/security/UnresolvedPermission.java @@ -590,7 +590,7 @@ implements java.io.Serializable cfs.put(certType, cf); } // parse the certificate - byte[] encoded = IOUtils.readNBytes(ois, ois.readInt()); + byte[] encoded = IOUtils.readExactlyNBytes(ois, ois.readInt()); ByteArrayInputStream bais = new ByteArrayInputStream(encoded); try { certList.add(cf.generateCertificate(bais)); diff --git a/src/share/classes/java/security/cert/CRLReason.java b/src/share/classes/java/security/cert/CRLReason.java index ac0b9e9c24f418fc5d68134ddf6fd65251c80b7b..79d4729d0b8a48fd176fb744b8c730aed32bed50 100644 --- a/src/share/classes/java/security/cert/CRLReason.java +++ b/src/share/classes/java/security/cert/CRLReason.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2014, 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 @@ -27,8 +27,8 @@ package java.security.cert; /** * The CRLReason enumeration specifies the reason that a certificate - * is revoked, as defined in - * RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL + * is revoked, as defined in + * RFC 5280: Internet X.509 Public Key Infrastructure Certificate and CRL * Profile. * * @author Sean Mullan diff --git a/src/share/classes/java/security/cert/CertificateRevokedException.java b/src/share/classes/java/security/cert/CertificateRevokedException.java index d478a7901f2a8b29ba54c5014061ead862b610a5..98e434607bbaf8c1915f73a27fc4f52d72b83d05 100644 --- a/src/share/classes/java/security/cert/CertificateRevokedException.java +++ b/src/share/classes/java/security/cert/CertificateRevokedException.java @@ -239,7 +239,7 @@ public class CertificateRevokedException extends CertificateException { for (int i = 0; i < size; i++) { String oid = (String) ois.readObject(); boolean critical = ois.readBoolean(); - byte[] extVal = IOUtils.readNBytes(ois, ois.readInt()); + byte[] extVal = IOUtils.readExactlyNBytes(ois, ois.readInt()); Extension ext = sun.security.x509.Extension.newExtension (new ObjectIdentifier(oid), critical, extVal); extensions.put(oid, ext); diff --git a/src/share/classes/java/security/cert/PKIXReason.java b/src/share/classes/java/security/cert/PKIXReason.java index d58ded97541b43c5689b733bcf3b3d7ce4389a4c..e9c48729934364906ada2877f20fef42614d238e 100644 --- a/src/share/classes/java/security/cert/PKIXReason.java +++ b/src/share/classes/java/security/cert/PKIXReason.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2014, 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 @@ -28,7 +28,7 @@ package java.security.cert; /** * The {@code PKIXReason} enumerates the potential PKIX-specific reasons * that an X.509 certification path may be invalid according to the PKIX - * (RFC 3280) standard. These reasons are in addition to those of the + * (RFC 5280) standard. These reasons are in addition to those of the * {@code CertPathValidatorException.BasicReason} enumeration. * * @since 1.7 diff --git a/src/share/classes/java/security/cert/TrustAnchor.java b/src/share/classes/java/security/cert/TrustAnchor.java index c98bf814caf85a3a297ad79db1b2cde9d647a160..e5be6a6daac698060744777be6cc14a685a75b46 100644 --- a/src/share/classes/java/security/cert/TrustAnchor.java +++ b/src/share/classes/java/security/cert/TrustAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -78,7 +78,7 @@ public class TrustAnchor { * The name constraints are specified as a byte array. This byte array * should contain the DER encoded form of the name constraints, as they * would appear in the NameConstraints structure defined in - * RFC 3280 + * RFC 5280 * and X.509. The ASN.1 definition of this structure appears below. * *
    {@code
    @@ -140,7 +140,7 @@ public class TrustAnchor {
          * 

    * The name constraints are specified as a byte array. This byte array * contains the DER encoded form of the name constraints, as they - * would appear in the NameConstraints structure defined in RFC 3280 + * would appear in the NameConstraints structure defined in RFC 5280 * and X.509. The ASN.1 notation for this structure is supplied in the * documentation for * {@link #TrustAnchor(X509Certificate, byte[]) @@ -179,7 +179,7 @@ public class TrustAnchor { *

    * The name constraints are specified as a byte array. This byte array * contains the DER encoded form of the name constraints, as they - * would appear in the NameConstraints structure defined in RFC 3280 + * would appear in the NameConstraints structure defined in RFC 5280 * and X.509. The ASN.1 notation for this structure is supplied in the * documentation for * {@link #TrustAnchor(X509Certificate, byte[]) @@ -294,7 +294,7 @@ public class TrustAnchor { *

    * The name constraints are returned as a byte array. This byte array * contains the DER encoded form of the name constraints, as they - * would appear in the NameConstraints structure defined in RFC 3280 + * would appear in the NameConstraints structure defined in RFC 5280 * and X.509. The ASN.1 notation for this structure is supplied in the * documentation for * {@link #TrustAnchor(X509Certificate, byte[]) diff --git a/src/share/classes/java/security/cert/X509CRL.java b/src/share/classes/java/security/cert/X509CRL.java index 0a40f45452d89c6029175c4183e3dbb04218c455..2b48ceb7bb842e519b68ffb7d07929a1d9a29456 100644 --- a/src/share/classes/java/security/cert/X509CRL.java +++ b/src/share/classes/java/security/cert/X509CRL.java @@ -66,7 +66,7 @@ import sun.security.util.SignatureUtil; *

    *

    * More information can be found in - * RFC 3280: Internet X.509 + * RFC 5280: Internet X.509 * Public Key Infrastructure Certificate and CRL Profile. *

    * The ASN.1 definition of {@code tbsCertList} is: diff --git a/src/share/classes/java/security/cert/X509CRLSelector.java b/src/share/classes/java/security/cert/X509CRLSelector.java index face5ff525d98d6f282adc57c808f94afef19c41..cf2e6b446ecfceb333084b9f8eaf67f2ce46e7a0 100644 --- a/src/share/classes/java/security/cert/X509CRLSelector.java +++ b/src/share/classes/java/security/cert/X509CRLSelector.java @@ -52,7 +52,7 @@ import sun.security.x509.X500Name; * {@link CertStore#getCRLs CertStore.getCRLs} or some similar * method. *

    - * Please refer to RFC 3280: + * Please refer to RFC 5280: * Internet X.509 Public Key Infrastructure Certificate and CRL Profile * for definitions of the X.509 CRL fields and extensions mentioned below. *

    diff --git a/src/share/classes/java/security/cert/X509CertSelector.java b/src/share/classes/java/security/cert/X509CertSelector.java index 0fe97a602048333d39efc7f186ef30967f8b9575..905e45401e94c91d5f5b08aaeb0ac9c588393ba3 100644 --- a/src/share/classes/java/security/cert/X509CertSelector.java +++ b/src/share/classes/java/security/cert/X509CertSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -65,7 +65,7 @@ import sun.security.x509.*; * number. Other unique combinations include the issuer, subject, * subjectKeyIdentifier and/or the subjectPublicKey criteria. *

    - * Please refer to RFC 3280: + * Please refer to RFC 5280: * Internet X.509 Public Key Infrastructure Certificate and CRL Profile for * definitions of the X.509 certificate extensions mentioned below. *

    @@ -728,7 +728,7 @@ public class X509CertSelector implements CertSelector { * The name is provided in string format. * RFC 822, DNS, and URI * names use the well-established string formats for those types (subject to - * the restrictions included in RFC 3280). IPv4 address names are + * the restrictions included in RFC 5280). IPv4 address names are * supplied using dotted quad notation. OID address names are represented * as a series of nonnegative integers separated by periods. And * directory names (distinguished names) are supplied in RFC 2253 format. @@ -746,7 +746,7 @@ public class X509CertSelector implements CertSelector { * String form of some distinguished names. * * @param type the name type (0-8, as specified in - * RFC 3280, section 4.2.1.7) + * RFC 5280, section 4.2.1.6) * @param name the name in string form (not {@code null}) * @throws IOException if a parsing error occurs */ @@ -770,7 +770,7 @@ public class X509CertSelector implements CertSelector { *

    * The name is provided as a byte array. This byte array should contain * the DER encoded name, as it would appear in the GeneralName structure - * defined in RFC 3280 and X.509. The encoded byte array should only contain + * defined in RFC 5280 and X.509. The encoded byte array should only contain * the encoded value of the name, and should not include the tag associated * with the name in the GeneralName structure. The ASN.1 definition of this * structure appears below. @@ -806,7 +806,7 @@ public class X509CertSelector implements CertSelector { * must contain the specified subjectAlternativeName. * * @param type the name type (0-8, as specified in - * RFC 3280, section 4.2.1.7) + * RFC 5280, section 4.2.1.6) * @param name the name in string or byte array form * @throws IOException if a parsing error occurs */ @@ -995,7 +995,7 @@ public class X509CertSelector implements CertSelector { *

    * The name constraints are specified as a byte array. This byte array * should contain the DER encoded form of the name constraints, as they - * would appear in the NameConstraints structure defined in RFC 3280 + * would appear in the NameConstraints structure defined in RFC 5280 * and X.509. The ASN.1 definition of this structure appears below. * *

    {@code
    @@ -1197,7 +1197,7 @@ public class X509CertSelector implements CertSelector {
          * 

    * The name is provided in string format. RFC 822, DNS, and URI names * use the well-established string formats for those types (subject to - * the restrictions included in RFC 3280). IPv4 address names are + * the restrictions included in RFC 5280). IPv4 address names are * supplied using dotted quad notation. OID address names are represented * as a series of nonnegative integers separated by periods. And * directory names (distinguished names) are supplied in RFC 2253 format. @@ -1214,7 +1214,7 @@ public class X509CertSelector implements CertSelector { * String form of some distinguished names. * * @param type the name type (0-8, as specified in - * RFC 3280, section 4.2.1.7) + * RFC 5280, section 4.2.1.6) * @param name the name in string form * @throws IOException if a parsing error occurs */ @@ -1234,7 +1234,7 @@ public class X509CertSelector implements CertSelector { *

    * The name is provided as a byte array. This byte array should contain * the DER encoded name, as it would appear in the GeneralName structure - * defined in RFC 3280 and X.509. The ASN.1 definition of this structure + * defined in RFC 5280 and X.509. The ASN.1 definition of this structure * appears in the documentation for * {@link #addSubjectAlternativeName(int type, byte [] name) * addSubjectAlternativeName(int type, byte [] name)}. @@ -1243,7 +1243,7 @@ public class X509CertSelector implements CertSelector { * subsequent modifications. * * @param type the name type (0-8, as specified in - * RFC 3280, section 4.2.1.7) + * RFC 5280, section 4.2.1.6) * @param name a byte array containing the name in ASN.1 DER encoded form * @throws IOException if a parsing error occurs */ @@ -1258,7 +1258,7 @@ public class X509CertSelector implements CertSelector { * the specified pathToName. * * @param type the name type (0-8, as specified in - * RFC 3280, section 4.2.1.7) + * RFC 5280, section 4.2.1.6) * @param name the name in string or byte array form * @throws IOException if an encoding error occurs (incorrect form for DN) */ @@ -1715,7 +1715,7 @@ public class X509CertSelector implements CertSelector { *

    * The name constraints are returned as a byte array. This byte array * contains the DER encoded form of the name constraints, as they - * would appear in the NameConstraints structure defined in RFC 3280 + * would appear in the NameConstraints structure defined in RFC 5280 * and X.509. The ASN.1 notation for this structure is supplied in the * documentation for * {@link #setNameConstraints(byte [] bytes) setNameConstraints(byte [] bytes)}. diff --git a/src/share/classes/java/security/cert/X509Certificate.java b/src/share/classes/java/security/cert/X509Certificate.java index 68afe1adaff38113dfa6c545700e72222d5c2a11..b13866a457f4c95447a102545d7685c55fe39cfc 100644 --- a/src/share/classes/java/security/cert/X509Certificate.java +++ b/src/share/classes/java/security/cert/X509Certificate.java @@ -65,7 +65,7 @@ import sun.security.util.SignatureUtil; * CA such as a "root" CA. *

    * More information can be found in - * RFC 3280: Internet X.509 + * RFC 5280: Internet X.509 * Public Key Infrastructure Certificate and CRL Profile. *

    * The ASN.1 definition of {@code tbsCertificate} is: @@ -410,7 +410,7 @@ implements X509Extension { * Gets the {@code issuerUniqueID} value from the certificate. * The issuer unique identifier is present in the certificate * to handle the possibility of reuse of issuer names over time. - * RFC 3280 recommends that names not be reused and that + * RFC 5280 recommends that names not be reused and that * conforming certificates not make use of unique identifiers. * Applications conforming to that profile should be capable of * parsing unique identifiers and making comparisons. @@ -461,7 +461,7 @@ implements X509Extension { * encipherOnly (7), * decipherOnly (8) } *

    - * RFC 3280 recommends that when used, this be marked + * RFC 5280 recommends that when used, this be marked * as a critical extension. * * @return the KeyUsage extension of this certificate, represented as @@ -574,7 +574,7 @@ implements X509Extension { * RFC 822, DNS, and URI * names are returned as {@code String}s, * using the well-established string formats for those types (subject to - * the restrictions included in RFC 3280). IPv4 address names are + * the restrictions included in RFC 5280). IPv4 address names are * returned using dotted quad notation. IPv6 address names are returned * in the form "a1:a2:...:a8", where a1-a8 are hexadecimal values * representing the eight 16-bit pieces of the address. OID names are diff --git a/src/share/classes/java/util/jar/JarFile.java b/src/share/classes/java/util/jar/JarFile.java index 940dfb679a4112b0dbfffd0fb44dd93706e437b9..dd6d1a413764cb92603217bb6d579b69612ed947 100644 --- a/src/share/classes/java/util/jar/JarFile.java +++ b/src/share/classes/java/util/jar/JarFile.java @@ -422,7 +422,12 @@ class JarFile extends ZipFile { */ private byte[] getBytes(ZipEntry ze) throws IOException { try (InputStream is = super.getInputStream(ze)) { - return IOUtils.readFully(is, (int)ze.getSize(), true); + int len = (int)ze.getSize(); + byte[] b = IOUtils.readAllBytes(is); + if (len != -1 && b.length != len) + throw new EOFException("Expected:" + len + ", read:" + b.length); + + return b; } } diff --git a/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java b/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java index 71cc0aa50ec2791c8dbf98848587ae6d6993dfcc..ff399839b2e5fadcc2c366939594e05d2d10aa13 100644 --- a/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java +++ b/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java @@ -33,6 +33,22 @@ class JavaxSecurityAuthKerberosAccessImpl KeyTab ktab) { return ktab.takeSnapshot(); } + + public KerberosPrincipal kerberosTicketGetClientAlias(KerberosTicket t) { + return t.clientAlias; + } + + public void kerberosTicketSetClientAlias(KerberosTicket t, KerberosPrincipal a) { + t.clientAlias = a; + } + + public KerberosPrincipal kerberosTicketGetServerAlias(KerberosTicket t) { + return t.serverAlias; + } + + public void kerberosTicketSetServerAlias(KerberosTicket t, KerberosPrincipal a) { + t.serverAlias = a; + } public KerberosTicket kerberosTicketGetProxy(KerberosTicket t) { return t.proxy; } diff --git a/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java b/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java index 308b619e99881731054d9f20eda28ac5a186671e..ef767f02e87c05f7c15ac78ca26ad8db35a74d5a 100644 --- a/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java +++ b/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -80,6 +80,11 @@ public final class KerberosPrincipal public static final int KRB_NT_UID = 5; + /** + * Enterprise name (alias) + */ + static final int KRB_NT_ENTERPRISE = 10; + private transient String fullName; private transient String realm; diff --git a/src/share/classes/javax/security/auth/kerberos/KerberosTicket.java b/src/share/classes/javax/security/auth/kerberos/KerberosTicket.java index 0327f04db585e82587b34dc56230a72622394560..3f29d9ba9589acbc4e27a0587add2bf26b58cda1 100644 --- a/src/share/classes/javax/security/auth/kerberos/KerberosTicket.java +++ b/src/share/classes/javax/security/auth/kerberos/KerberosTicket.java @@ -194,6 +194,10 @@ public class KerberosTicket implements Destroyable, Refreshable, private InetAddress[] clientAddresses; + transient KerberosPrincipal clientAlias = null; + + transient KerberosPrincipal serverAlias = null; + /** * Evidence ticket if proxy_impersonator. This field can be accessed * by KerberosSecrets. It's serialized. @@ -308,11 +312,7 @@ public class KerberosTicket implements Destroyable, Refreshable, } else this.flags = new boolean[NUM_FLAGS]; - if (this.flags[RENEWABLE_TICKET_FLAG]) { - if (renewTill == null) - throw new IllegalArgumentException("The renewable period " - + "end time cannot be null for renewable tickets."); - + if (this.flags[RENEWABLE_TICKET_FLAG] && renewTill != null) { this.renewTill = new Date(renewTill.getTime()); } @@ -553,6 +553,11 @@ public class KerberosTicket implements Destroyable, Refreshable, if (!isRenewable()) throw new RefreshFailedException("This ticket is not renewable"); + if (getRenewTill() == null) { + // Renewable ticket without renew-till. Illegal and ignored. + return; + } + if (System.currentTimeMillis() > getRenewTill().getTime()) throw new RefreshFailedException("This ticket is past " + "its last renewal time."); @@ -562,7 +567,11 @@ public class KerberosTicket implements Destroyable, Refreshable, try { krb5Creds = new sun.security.krb5.Credentials(asn1Encoding, client.toString(), + (clientAlias != null ? + clientAlias.getName() : null), server.toString(), + (serverAlias != null ? + serverAlias.getName() : null), sessionKey.getEncoded(), sessionKey.getKeyType(), flags, diff --git a/src/share/classes/javax/security/auth/x500/X500Principal.java b/src/share/classes/javax/security/auth/x500/X500Principal.java index 77292b0be22f29ce7cde390d8cdf5f4a7ea225d6..22366610981252b3bb644c65a0d8786ef578be18 100644 --- a/src/share/classes/javax/security/auth/x500/X500Principal.java +++ b/src/share/classes/javax/security/auth/x500/X500Principal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -41,13 +41,13 @@ import sun.security.util.*; * of the distinguished name, or by using the ASN.1 DER encoded byte * representation of the distinguished name. The current specification * for the string representation of a distinguished name is defined in - * RFC 2253: Lightweight + * RFC 2253: Lightweight * Directory Access Protocol (v3): UTF-8 String Representation of * Distinguished Names. This class, however, accepts string formats from - * both RFC 2253 and RFC 1779: + * both RFC 2253 and RFC 1779: * A String Representation of Distinguished Names, and also recognizes * attribute type keywords whose OIDs (Object Identifiers) are defined in - * RFC 3280: Internet X.509 + * RFC 5280: Internet X.509 * Public Key Infrastructure Certificate and CRL Profile. * *

    The string representation for this {@code X500Principal} @@ -108,7 +108,7 @@ public final class X500Principal implements Principal, java.io.Serializable { * (and listed in {@link #getName(String format) getName(String format)}), * as well as the T, DNQ or DNQUALIFIER, SURNAME, GIVENNAME, INITIALS, * GENERATION, EMAILADDRESS, and SERIALNUMBER keywords whose Object - * Identifiers (OIDs) are defined in RFC 3280 and its successor. + * Identifiers (OIDs) are defined in RFC 5280. * Any other attribute type must be specified as an OID. * *

    This implementation enforces a more restrictive OID syntax than @@ -456,7 +456,7 @@ public final class X500Principal implements Principal, java.io.Serializable { * (obtained via the {@code getName(X500Principal.CANONICAL)} method) * of this object and o are equal. * - *

    This implementation is compliant with the requirements of RFC 3280. + *

    This implementation is compliant with the requirements of RFC 5280. * * @param o Object to be compared for equality with this * {@code X500Principal} diff --git a/src/share/classes/javax/security/auth/x500/package-info.java b/src/share/classes/javax/security/auth/x500/package-info.java index 12f8a5322d1e0d993f66111c46e8d104d34d991a..1e9ca1a82405a4ff175e838d7f0c6082eede7733 100644 --- a/src/share/classes/javax/security/auth/x500/package-info.java +++ b/src/share/classes/javax/security/auth/x500/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -31,15 +31,15 @@ *

    Package Specification

    * * diff --git a/src/share/classes/jdk/internal/util/StaticProperty.java b/src/share/classes/jdk/internal/util/StaticProperty.java new file mode 100644 index 0000000000000000000000000000000000000000..1ac81df42ca692fcf356b0c061c8cd748c729efc --- /dev/null +++ b/src/share/classes/jdk/internal/util/StaticProperty.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018, 2019, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package jdk.internal.util; + +/** + * System Property access for internal use only. + * Read-only access to System property values initialized during Phase 1 + * are cached. Setting, clearing, or modifying the value using + * {@link System#setProperty) or {@link System#getProperties()} is ignored. + * {@link SecurityManager#checkPropertyAccess} is NOT checked + * in these access methods. The caller of these methods should take care to ensure + * that the returned property is not made accessible to untrusted code. + */ +public final class StaticProperty { + + // The class static initialization is triggered to initialize these final + // fields during init Phase 1 and before a security manager is set. + private static final String JDK_SERIAL_FILTER = System.getProperty("jdk.serialFilter"); + + private StaticProperty() {} + + /** + * + * Return the {@code jdk.serialFilter} system property. + * + * {@link SecurityManager#checkPropertyAccess} is NOT checked + * in this method. The caller of this method should take care to ensure + * that the returned property is not made accessible to untrusted code. + * + * @return the {@code user.name} system property + */ + public static String jdkSerialFilter() { + return JDK_SERIAL_FILTER; + } +} diff --git a/src/share/classes/sun/applet/AppletClassLoader.java b/src/share/classes/sun/applet/AppletClassLoader.java index f732ad224252dd80370d68fa43084b7d18fd9afd..1fcd1585ec27ec485822d920f8b44805c5553963 100644 --- a/src/share/classes/sun/applet/AppletClassLoader.java +++ b/src/share/classes/sun/applet/AppletClassLoader.java @@ -33,6 +33,7 @@ import java.net.URLConnection; import java.net.MalformedURLException; import java.net.InetAddress; import java.net.UnknownHostException; +import java.io.EOFException; import java.io.File; import java.io.FilePermission; import java.io.IOException; @@ -333,7 +334,9 @@ public class AppletClassLoader extends URLClassLoader { byte[] b; try { - b = IOUtils.readFully(in, len, true); + b = IOUtils.readAllBytes(in); + if (len != -1 && b.length != len) + throw new EOFException("Expected:" + len + ", read:" + b.length); } finally { in.close(); } diff --git a/src/share/classes/sun/misc/IOUtils.java b/src/share/classes/sun/misc/IOUtils.java index 67079b9a671a1803d9f753cdd292ed76e89df1aa..5e6c79cb6467649cf051ad97632e6c7c55dcd3ed 100644 --- a/src/share/classes/sun/misc/IOUtils.java +++ b/src/share/classes/sun/misc/IOUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, 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 @@ -32,67 +32,282 @@ package sun.misc; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; + +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; +import java.util.Objects; public class IOUtils { + private static final int DEFAULT_BUFFER_SIZE = 8192; + /** - * Read up to {@code length} of bytes from {@code in} - * until EOF is detected. + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; + + /** + * Read exactly {@code length} of bytes from {@code in}. + * + *

    Note that this method is safe to be called with unknown large + * {@code length} argument. The memory used is proportional to the + * actual bytes available. An exception is thrown if there are not + * enough bytes in the stream. + * * @param is input stream, must not be null - * @param length number of bytes to read, -1 or Integer.MAX_VALUE means - * read as much as possible - * @param readAll if true, an EOFException will be thrown if not enough - * bytes are read. Ignored when length is -1 or Integer.MAX_VALUE + * @param length number of bytes to read * @return bytes read - * @throws IOException Any IO error or a premature EOF is detected + * @throws EOFException if there are not enough bytes in the stream + * @throws IOException if an I/O error occurs or {@code length} is negative + * @throws OutOfMemoryError if an array of the required size cannot be + * allocated. */ - public static byte[] readFully(InputStream is, int length, boolean readAll) + public static byte[] readExactlyNBytes(InputStream is, int length) throws IOException { - byte[] output = {}; - if (length == -1) length = Integer.MAX_VALUE; - int pos = 0; - while (pos < length) { - int bytesToRead; - if (pos >= output.length) { // Only expand when there's no room - bytesToRead = Math.min(length - pos, output.length + 1024); - if (output.length < pos + bytesToRead) { - output = Arrays.copyOf(output, pos + bytesToRead); - } - } else { - bytesToRead = output.length - pos; + if (length < 0) { + throw new IOException("length cannot be negative: " + length); + } + byte[] data = readNBytes(is, length); + if (data.length < length) { + throw new EOFException(); + } + return data; + } + + /** + * Reads all remaining bytes from the input stream. This method blocks until + * all remaining bytes have been read and end of stream is detected, or an + * exception is thrown. This method does not close the input stream. + * + *

    When this stream reaches end of stream, further invocations of this + * method will return an empty byte array. + * + *

    Note that this method is intended for simple cases where it is + * convenient to read all bytes into a byte array. It is not intended for + * reading input streams with large amounts of data. + * + *

    The behavior for the case where the input stream is asynchronously + * closed, or the thread interrupted during the read, is highly input + * stream specific, and therefore not specified. + * + *

    If an I/O error occurs reading from the input stream, then it may do + * so after some, but not all, bytes have been read. Consequently the input + * stream may not be at end of stream and may be in an inconsistent state. + * It is strongly recommended that the stream be promptly closed if an I/O + * error occurs. + * + * @implSpec + * This method invokes {@link #readNBytes(int)} with a length of + * {@link Integer#MAX_VALUE}. + * + * @param is input stream, must not be null + * @return a byte array containing the bytes read from this input stream + * @throws IOException if an I/O error occurs + * @throws OutOfMemoryError if an array of the required size cannot be + * allocated. + * + * @since 1.9 + */ + public static byte[] readAllBytes(InputStream is) throws IOException { + return readNBytes(is, Integer.MAX_VALUE); + } + + /** + * Reads up to a specified number of bytes from the input stream. This + * method blocks until the requested number of bytes have been read, end + * of stream is detected, or an exception is thrown. This method does not + * close the input stream. + * + *

    The length of the returned array equals the number of bytes read + * from the stream. If {@code len} is zero, then no bytes are read and + * an empty byte array is returned. Otherwise, up to {@code len} bytes + * are read from the stream. Fewer than {@code len} bytes may be read if + * end of stream is encountered. + * + *

    When this stream reaches end of stream, further invocations of this + * method will return an empty byte array. + * + *

    Note that this method is intended for simple cases where it is + * convenient to read the specified number of bytes into a byte array. The + * total amount of memory allocated by this method is proportional to the + * number of bytes read from the stream which is bounded by {@code len}. + * Therefore, the method may be safely called with very large values of + * {@code len} provided sufficient memory is available. + * + *

    The behavior for the case where the input stream is asynchronously + * closed, or the thread interrupted during the read, is highly input + * stream specific, and therefore not specified. + * + *

    If an I/O error occurs reading from the input stream, then it may do + * so after some, but not all, bytes have been read. Consequently the input + * stream may not be at end of stream and may be in an inconsistent state. + * It is strongly recommended that the stream be promptly closed if an I/O + * error occurs. + * + * @implNote + * The number of bytes allocated to read data from this stream and return + * the result is bounded by {@code 2*(long)len}, inclusive. + * + * @param is input stream, must not be null + * @param len the maximum number of bytes to read + * @return a byte array containing the bytes read from this input stream + * @throws IllegalArgumentException if {@code length} is negative + * @throws IOException if an I/O error occurs + * @throws OutOfMemoryError if an array of the required size cannot be + * allocated. + * + * @since 11 + */ + public static byte[] readNBytes(InputStream is, int len) throws IOException { + if (len < 0) { + throw new IllegalArgumentException("len < 0"); + } + + List bufs = null; + byte[] result = null; + int total = 0; + int remaining = len; + int n; + do { + byte[] buf = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)]; + int nread = 0; + + // read to EOF which may read more or less than buffer size + while ((n = is.read(buf, nread, + Math.min(buf.length - nread, remaining))) > 0) { + nread += n; + remaining -= n; } - int cc = is.read(output, pos, bytesToRead); - if (cc < 0) { - if (readAll && length != Integer.MAX_VALUE) { - throw new EOFException("Detect premature EOF"); + + if (nread > 0) { + if (MAX_BUFFER_SIZE - total < nread) { + throw new OutOfMemoryError("Required array size too large"); + } + total += nread; + if (result == null) { + result = buf; } else { - if (output.length != pos) { - output = Arrays.copyOf(output, pos); + if (bufs == null) { + bufs = new ArrayList<>(); + bufs.add(result); } - break; + bufs.add(buf); } } - pos += cc; + // if the last call to read returned -1 or the number of bytes + // requested have been read then break + } while (n >= 0 && remaining > 0); + + if (bufs == null) { + if (result == null) { + return new byte[0]; + } + return result.length == total ? + result : Arrays.copyOf(result, total); + } + + result = new byte[total]; + int offset = 0; + remaining = total; + for (byte[] b : bufs) { + int count = Math.min(b.length, remaining); + System.arraycopy(b, 0, result, offset, count); + offset += count; + remaining -= count; + } + + return result; + } + + /** + * Reads the requested number of bytes from the input stream into the given + * byte array. This method blocks until {@code len} bytes of input data have + * been read, end of stream is detected, or an exception is thrown. The + * number of bytes actually read, possibly zero, is returned. This method + * does not close the input stream. + * + *

    In the case where end of stream is reached before {@code len} bytes + * have been read, then the actual number of bytes read will be returned. + * When this stream reaches end of stream, further invocations of this + * method will return zero. + * + *

    If {@code len} is zero, then no bytes are read and {@code 0} is + * returned; otherwise, there is an attempt to read up to {@code len} bytes. + * + *

    The first byte read is stored into element {@code b[off]}, the next + * one in to {@code b[off+1]}, and so on. The number of bytes read is, at + * most, equal to {@code len}. Let k be the number of bytes actually + * read; these bytes will be stored in elements {@code b[off]} through + * {@code b[off+}k{@code -1]}, leaving elements {@code b[off+}k + * {@code ]} through {@code b[off+len-1]} unaffected. + * + *

    The behavior for the case where the input stream is asynchronously + * closed, or the thread interrupted during the read, is highly input + * stream specific, and therefore not specified. + * + *

    If an I/O error occurs reading from the input stream, then it may do + * so after some, but not all, bytes of {@code b} have been updated with + * data from the input stream. Consequently the input stream and {@code b} + * may be in an inconsistent state. It is strongly recommended that the + * stream be promptly closed if an I/O error occurs. + * + * @param is input stream, must not be null + * @param b the byte array into which the data is read + * @param off the start offset in {@code b} at which the data is written + * @param len the maximum number of bytes to read + * @return the actual number of bytes read into the buffer + * @throws IOException if an I/O error occurs + * @throws NullPointerException if {@code b} is {@code null} + * @throws IndexOutOfBoundsException If {@code off} is negative, {@code len} + * is negative, or {@code len} is greater than {@code b.length - off} + * + * @since 1.9 + */ + public static int readNBytes(InputStream is, byte[] b, int off, int len) throws IOException { + Objects.requireNonNull(b); + if (off < 0 || len < 0 || len > b.length - off) + throw new IndexOutOfBoundsException(); + int n = 0; + while (n < len) { + int count = is.read(b, off + n, len - n); + if (count < 0) + break; + n += count; } - return output; + return n; } /** - * Read {@code length} of bytes from {@code in}. An exception is - * thrown if there are not enough bytes in the stream. + * Compatibility wrapper for third party users of + * {@code sun.misc.IOUtils.readFully} following its + * removal in JDK-8231139. + * + * Read up to {@code length} of bytes from {@code in} + * until EOF is detected. * * @param is input stream, must not be null - * @param length number of bytes to read, must not be negative + * @param length number of bytes to read + * @param readAll if true, an EOFException will be thrown if not enough + * bytes are read. * @return bytes read - * @throws IOException if any IO error or a premature EOF is detected, or - * if {@code length} is negative since this length is usually also - * read from {@code is}. + * @throws EOFException if there are not enough bytes in the stream + * @throws IOException if an I/O error occurs or {@code length} is negative + * @throws OutOfMemoryError if an array of the required size cannot be + * allocated. */ - public static byte[] readNBytes(InputStream is, int length) throws IOException { + public static byte[] readFully(InputStream is, int length, boolean readAll) + throws IOException { if (length < 0) { throw new IOException("length cannot be negative: " + length); } - return readFully(is, length, true); + if (readAll) { + return readExactlyNBytes(is, length); + } else { + return readNBytes(is, length); + } } } diff --git a/src/share/classes/sun/misc/JavaObjectInputStreamReadString.java b/src/share/classes/sun/misc/JavaObjectInputStreamReadString.java new file mode 100644 index 0000000000000000000000000000000000000000..ed7a6c3e6601a17f763024727acdadac97e88741 --- /dev/null +++ b/src/share/classes/sun/misc/JavaObjectInputStreamReadString.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.misc; + +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * Interface to specify methods for accessing {@code ObjectInputStream}. + */ +@FunctionalInterface +public interface JavaObjectInputStreamReadString { + String readString(ObjectInputStream ois) throws IOException; +} + diff --git a/src/share/classes/sun/misc/ObjectInputFilter.java b/src/share/classes/sun/misc/ObjectInputFilter.java index 9b2c6891d69b6805045739d9b53ffa811b8c6071..af21c740013b1e9cd212dc0e3e6e700adc1bad74 100644 --- a/src/share/classes/sun/misc/ObjectInputFilter.java +++ b/src/share/classes/sun/misc/ObjectInputFilter.java @@ -37,6 +37,8 @@ import java.util.Optional; import java.util.function.Function; import sun.util.logging.PlatformLogger; +import jdk.internal.util.StaticProperty; + /** * Filter classes, array lengths, and graph metrics during deserialization. * If set on an {@link ObjectInputStream}, the {@link #checkInput checkInput(FilterInfo)} @@ -247,7 +249,7 @@ public interface ObjectInputFilter { static { configuredFilter = AccessController .doPrivileged((PrivilegedAction) () -> { - String props = System.getProperty(SERIAL_FILTER_PROPNAME); + String props = StaticProperty.jdkSerialFilter(); if (props == null) { props = Security.getProperty(SERIAL_FILTER_PROPNAME); } diff --git a/src/share/classes/sun/misc/SharedSecrets.java b/src/share/classes/sun/misc/SharedSecrets.java index 0e2509688d385f5413b7344acc5904dbe5992a26..f065a2c685df64995c0e5bd75dfbad6f376b35aa 100644 --- a/src/share/classes/sun/misc/SharedSecrets.java +++ b/src/share/classes/sun/misc/SharedSecrets.java @@ -60,6 +60,7 @@ public class SharedSecrets { private static JavaAWTAccess javaAWTAccess; private static JavaOISAccess javaOISAccess; private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess; + private static JavaObjectInputStreamReadString javaObjectInputStreamReadString; private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; private static JavaSecuritySignatureAccess javaSecuritySignatureAccess; @@ -204,8 +205,18 @@ public class SharedSecrets { return javaAWTAccess; } + public static JavaObjectInputStreamReadString getJavaObjectInputStreamReadString() { + if (javaObjectInputStreamReadString == null) { + unsafe.ensureClassInitialized(ObjectInputStream.class); + } + return javaObjectInputStreamReadString; + } + + public static void setJavaObjectInputStreamReadString(JavaObjectInputStreamReadString access) { + javaObjectInputStreamReadString = access; + } - public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() { + public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() { if (javaObjectInputStreamAccess == null) { unsafe.ensureClassInitialized(ObjectInputStream.class); } diff --git a/src/share/classes/sun/misc/URLClassPath.java b/src/share/classes/sun/misc/URLClassPath.java index 6e035105dfc002fea8d9373e10d32f4136b7d846..8d7593f263a0fce3f152339ba0bc989fd463284d 100644 --- a/src/share/classes/sun/misc/URLClassPath.java +++ b/src/share/classes/sun/misc/URLClassPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, 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 @@ -1229,10 +1229,15 @@ public class URLClassPath { int i = 0; while (st.hasMoreTokens()) { String path = st.nextToken(); - URL url = DISABLE_CP_URL_CHECK ? new URL(base, path) : safeResolve(base, path); + URL url = DISABLE_CP_URL_CHECK ? new URL(base, path) : tryResolve(base, path); if (url != null) { urls[i] = url; i++; + } else { + if (DEBUG_CP_URL_CHECK) { + System.err.println("Class-Path entry: \"" + path + + "\" ignored in JAR file " + base); + } } } if (i == 0) { @@ -1244,36 +1249,74 @@ public class URLClassPath { return urls; } - /* - * Return a URL for the given path resolved against the base URL, or - * null if the resulting URL is invalid. + static URL tryResolve(URL base, String input) throws MalformedURLException { + if ("file".equalsIgnoreCase(base.getProtocol())) { + return tryResolveFile(base, input); + } else { + return tryResolveNonFile(base, input); + } + } + + /** + * Attempt to return a file URL by resolving input against a base file + * URL. The input is an absolute or relative file URL that encodes a + * file path. + * + * @apiNote Nonsensical input such as a Windows file path with a drive + * letter cannot be disambiguated from an absolute URL so will be rejected + * (by returning null) by this method. + * + * @return the resolved URL or null if the input is an absolute URL with + * a scheme other than file (ignoring case) + * @throws MalformedURLException */ - static URL safeResolve(URL base, String path) { - String child = path.replace(File.separatorChar, '/'); - try { - if (!URI.create(child).isAbsolute()) { - URL url = new URL(base, child); - if (base.getProtocol().equalsIgnoreCase("file")) { - return url; - } else { - String bp = base.getPath(); - String urlp = url.getPath(); - int pos = bp.lastIndexOf('/'); - if (pos == -1) { - pos = bp.length() - 1; - } - if (urlp.regionMatches(0, bp, 0, pos + 1) - && urlp.indexOf("..", pos) == -1) { - return url; - } - } + static URL tryResolveFile(URL base, String input) throws MalformedURLException { + int index = input.indexOf(':'); + boolean isFile; + if (index >= 0) { + String scheme = input.substring(0, index); + isFile = "file".equalsIgnoreCase(scheme); + } else { + isFile = true; + } + return (isFile) ? new URL(base, input) : null; + } + + /** + * Attempt to return a URL by resolving input against a base URL. Returns + * null if the resolved URL is not contained by the base URL. + * + * @return the resolved URL or null + * @throws MalformedURLException + */ + static URL tryResolveNonFile(URL base, String input) throws MalformedURLException { + String child = input.replace(File.separatorChar, '/'); + if (isRelative(child)) { + URL url = new URL(base, child); + String bp = base.getPath(); + String urlp = url.getPath(); + int pos = bp.lastIndexOf('/'); + if (pos == -1) { + pos = bp.length() - 1; + } + if (urlp.regionMatches(0, bp, 0, pos + 1) + && urlp.indexOf("..", pos) == -1) { + return url; } - } catch (MalformedURLException | IllegalArgumentException e) {} - if (DEBUG_CP_URL_CHECK) { - System.err.println("Class-Path entry: \"" + path + "\" ignored in JAR file " + base); } return null; } + + /** + * Returns true if the given input is a relative URI. + */ + static boolean isRelative(String child) { + try { + return !URI.create(child).isAbsolute(); + } catch (IllegalArgumentException e) { + return false; + } + } } /* diff --git a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index 53e84d434734b7058df9b4437aee367e9305fc7d..b91093f49e8aa33d74e94435b2f23506f0ce8c5b 100644 --- a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -49,9 +49,6 @@ class DatagramChannelImpl // Our file descriptor private final FileDescriptor fd; - - // fd value needed for dev/poll. This value will remain valid - // even after the value in the file descriptor object has been set to -1 private final int fdVal; // The protocol family of the socket @@ -103,7 +100,6 @@ class DatagramChannelImpl // -- End of fields protected by stateLock - public DatagramChannelImpl(SelectorProvider sp) throws IOException { @@ -138,16 +134,27 @@ class DatagramChannelImpl throw new UnsupportedOperationException("IPv6 not available"); } } - this.family = family; - this.fd = Net.socket(family, false); - this.fdVal = IOUtil.fdVal(fd); - this.state = ST_UNCONNECTED; + + ResourceManager.beforeUdpCreate(); + try { + this.family = family; + this.fd = Net.socket(family, false); + this.fdVal = IOUtil.fdVal(fd); + this.state = ST_UNCONNECTED; + } catch (IOException ioe) { + ResourceManager.afterUdpClose(); + throw ioe; + } } public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException { super(sp); + + // increment UDP count to match decrement when closing + ResourceManager.beforeUdpCreate(); + this.family = Net.isIPv6Available() ? StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; this.fd = fd; @@ -742,10 +749,9 @@ class DatagramChannelImpl localAddress = Net.localAddress(fd); // flush any packets already received. - boolean blocking = false; synchronized (blockingLock()) { + boolean blocking = isBlocking(); try { - blocking = isBlocking(); // remainder of each packet thrown away ByteBuffer tmpBuf = ByteBuffer.allocate(1); if (blocking) { diff --git a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java index fe2ed23000262dfecbb99f7f918d96926238c2b6..838a02d03144b08eaf33795207b3728fd0b08212 100644 --- a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2018, 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 @@ -25,10 +25,22 @@ package sun.nio.ch; -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.DatagramSocketImpl; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketOption; +import java.net.SocketTimeoutException; +import java.net.StandardSocketOptions; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.IllegalBlockingModeException; // Make a datagram-socket channel look like a datagram socket. @@ -178,7 +190,6 @@ public class DatagramSocketAdaptor dc.configureBlocking(false); try { - int n; SocketAddress sender; if ((sender = dc.receive(bb)) != null) return sender; @@ -188,19 +199,18 @@ public class DatagramSocketAdaptor throw new ClosedChannelException(); long st = System.currentTimeMillis(); int result = dc.poll(Net.POLLIN, to); - if (result > 0 && - ((result & Net.POLLIN) != 0)) { + if (result > 0 && ((result & Net.POLLIN) != 0)) { if ((sender = dc.receive(bb)) != null) return sender; } to -= System.currentTimeMillis() - st; if (to <= 0) throw new SocketTimeoutException(); - } } finally { - if (dc.isOpen()) + try { dc.configureBlocking(true); + } catch (ClosedChannelException e) { } } } diff --git a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java index 4357ffc4e73bc85033e3adaa8804459911823125..63574acc7893250f2fa27aadb05f3e2b0417c16c 100644 --- a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -25,9 +25,20 @@ package sun.nio.ch; -import java.io.*; -import java.net.*; -import java.nio.channels.*; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.StandardSocketOptions; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.NotYetBoundException; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; // Make a server-socket channel look like a server socket. @@ -37,7 +48,7 @@ import java.nio.channels.*; // class. // -public class ServerSocketAdaptor // package-private +class ServerSocketAdaptor // package-private extends ServerSocket { @@ -97,12 +108,16 @@ public class ServerSocketAdaptor // package-private throw new IllegalBlockingModeException(); try { if (timeout == 0) { + // for compatibility reasons: accept connection if available + // when configured non-blocking SocketChannel sc = ssc.accept(); if (sc == null && !ssc.isBlocking()) throw new IllegalBlockingModeException(); return sc.socket(); } + if (!ssc.isBlocking()) + throw new IllegalBlockingModeException(); ssc.configureBlocking(false); try { SocketChannel sc; @@ -121,10 +136,10 @@ public class ServerSocketAdaptor // package-private throw new SocketTimeoutException(); } } finally { - if (ssc.isOpen()) + try { ssc.configureBlocking(true); + } catch (ClosedChannelException e) { } } - } catch (Exception x) { Net.translateException(x); assert false; @@ -178,8 +193,7 @@ public class ServerSocketAdaptor // package-private if (!isBound()) return "ServerSocket[unbound]"; return "ServerSocket[addr=" + getInetAddress() + - // ",port=" + getPort() + - ",localport=" + getLocalPort() + "]"; + ",localport=" + getLocalPort() + "]"; } public void setReceiveBufferSize(int size) throws SocketException { diff --git a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index ee5ff7675babf8e89fbce431d237ccc7a1b6ab4f..563f948cf924bc804e248c06a1182cb7b0f66138 100644 --- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -48,10 +48,7 @@ class ServerSocketChannelImpl // Our file descriptor private final FileDescriptor fd; - - // fd value needed for dev/poll. This value will remain valid - // even after the value in the file descriptor object has been set to -1 - private int fdVal; + private final int fdVal; // ID of native thread currently blocked in this channel, for signalling private volatile long thread = 0; diff --git a/src/share/classes/sun/nio/ch/SocketAdaptor.java b/src/share/classes/sun/nio/ch/SocketAdaptor.java index d115b7aaf6097b6f6ad9918cfe6ef4e6c6667b3c..c128dc53c19304ad66e8d9194327860236f902bb 100644 --- a/src/share/classes/sun/nio/ch/SocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/SocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -25,11 +25,23 @@ package sun.nio.ch; -import java.io.*; -import java.lang.ref.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketImpl; +import java.net.SocketOption; +import java.net.SocketTimeoutException; +import java.net.StandardSocketOptions; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.SocketChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.util.*; @@ -47,7 +59,7 @@ import java.util.*; // java.net.Socket so as to simplify tracking future changes to that class. // -public class SocketAdaptor +class SocketAdaptor extends Socket { @@ -91,7 +103,6 @@ public class SocketAdaptor throw new IllegalBlockingModeException(); try { - if (timeout == 0) { sc.connect(remote); return; @@ -119,8 +130,9 @@ public class SocketAdaptor } } } finally { - if (sc.isOpen()) + try { sc.configureBlocking(true); + } catch (ClosedChannelException e) { } } } catch (Exception x) { @@ -188,10 +200,11 @@ public class SocketAdaptor synchronized (sc.blockingLock()) { if (!sc.isBlocking()) throw new IllegalBlockingModeException(); + if (timeout == 0) return sc.read(bb); - sc.configureBlocking(false); + sc.configureBlocking(false); try { int n; if ((n = sc.read(bb)) != 0) @@ -211,10 +224,10 @@ public class SocketAdaptor throw new SocketTimeoutException(); } } finally { - if (sc.isOpen()) + try { sc.configureBlocking(true); + } catch (ClosedChannelException e) { } } - } } } diff --git a/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/share/classes/sun/nio/ch/SocketChannelImpl.java index 7b694efe6ade1c48b9f56dd3130f7443c6f485a6..164a1656613733294fc869cc5c81afddbf191e48 100644 --- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -50,9 +50,6 @@ class SocketChannelImpl // Our file descriptor object private final FileDescriptor fd; - - // fd value needed for dev/poll. This value will remain valid - // even after the value in the file descriptor object has been set to -1 private final int fdVal; // IDs of native threads doing reads and writes, for signalling diff --git a/src/share/classes/sun/reflect/misc/MethodUtil.java b/src/share/classes/sun/reflect/misc/MethodUtil.java index ebe802b60a2eff8d8f3f032fcaa22f66c75555bb..e48ec1d53ee4dc1f466336ec0a2a5f9c10b74d46 100644 --- a/src/share/classes/sun/reflect/misc/MethodUtil.java +++ b/src/share/classes/sun/reflect/misc/MethodUtil.java @@ -25,6 +25,7 @@ package sun.reflect.misc; +import java.io.EOFException; import java.security.AllPermission; import java.security.AccessController; import java.security.PermissionCollection; @@ -42,8 +43,8 @@ import java.lang.reflect.AccessibleObject; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; -import sun.misc.IOUtils; +import sun.misc.IOUtils; class Trampoline { static { @@ -382,15 +383,12 @@ public final class MethodUtil extends SecureClassLoader { } } int len = uc.getContentLength(); - InputStream in = new BufferedInputStream(uc.getInputStream()); - - byte[] b; - try { - b = IOUtils.readFully(in, len, true); - } finally { - in.close(); + try (InputStream in = new BufferedInputStream(uc.getInputStream())) { + byte[] b = IOUtils.readAllBytes(in); + if (len != -1 && b.length != len) + throw new EOFException("Expected:" + len + ", read:" + b.length); + return b; } - return b; } diff --git a/src/share/classes/sun/rmi/registry/RegistryImpl_Skel.java b/src/share/classes/sun/rmi/registry/RegistryImpl_Skel.java index c0a06f1f017e67507c4232b9f845441b3d8633cf..2d9102f1a62cb51c4027124e62a54b76774f520f 100644 --- a/src/share/classes/sun/rmi/registry/RegistryImpl_Skel.java +++ b/src/share/classes/sun/rmi/registry/RegistryImpl_Skel.java @@ -27,7 +27,9 @@ package sun.rmi.registry; import java.io.IOException; +import java.io.ObjectInputStream; +import sun.misc.SharedSecrets; import sun.rmi.transport.StreamRemoteCall; /** @@ -83,8 +85,9 @@ public final class RegistryImpl_Skel java.lang.String $param_String_1; java.rmi.Remote $param_Remote_2; try { - java.io.ObjectInput in = call.getInputStream(); - $param_String_1 = (java.lang.String) in.readObject(); + ObjectInputStream in = (ObjectInputStream)call.getInputStream(); + $param_String_1 = + SharedSecrets.getJavaObjectInputStreamReadString().readString(in); $param_Remote_2 = (java.rmi.Remote) in.readObject(); } catch (ClassCastException | IOException | ClassNotFoundException e) { call.discardPendingRefs(); @@ -118,9 +121,10 @@ public final class RegistryImpl_Skel { java.lang.String $param_String_1; try { - java.io.ObjectInput in = call.getInputStream(); - $param_String_1 = (java.lang.String) in.readObject(); - } catch (ClassCastException | IOException | ClassNotFoundException e) { + ObjectInputStream in = (ObjectInputStream)call.getInputStream(); + $param_String_1 = + SharedSecrets.getJavaObjectInputStreamReadString().readString(in); + } catch (ClassCastException | IOException e) { call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); } finally { @@ -144,8 +148,9 @@ public final class RegistryImpl_Skel java.lang.String $param_String_1; java.rmi.Remote $param_Remote_2; try { - java.io.ObjectInput in = call.getInputStream(); - $param_String_1 = (java.lang.String) in.readObject(); + ObjectInputStream in = (ObjectInputStream)call.getInputStream(); + $param_String_1 = + SharedSecrets.getJavaObjectInputStreamReadString().readString(in); $param_Remote_2 = (java.rmi.Remote) in.readObject(); } catch (ClassCastException | IOException | java.lang.ClassNotFoundException e) { call.discardPendingRefs(); @@ -169,9 +174,10 @@ public final class RegistryImpl_Skel java.lang.String $param_String_1; try { - java.io.ObjectInput in = call.getInputStream(); - $param_String_1 = (java.lang.String) in.readObject(); - } catch (ClassCastException | IOException | ClassNotFoundException e) { + ObjectInputStream in = (ObjectInputStream)call.getInputStream(); + $param_String_1 = + SharedSecrets.getJavaObjectInputStreamReadString().readString(in); + } catch (ClassCastException | IOException e) { call.discardPendingRefs(); throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); } finally { diff --git a/src/share/classes/sun/rmi/server/UnicastRef.java b/src/share/classes/sun/rmi/server/UnicastRef.java index 831c41bd9edb916a9831246788daa71f22a066c4..b01a2b87ec08b1f78c37a7cde5c886594f85c84f 100644 --- a/src/share/classes/sun/rmi/server/UnicastRef.java +++ b/src/share/classes/sun/rmi/server/UnicastRef.java @@ -27,6 +27,7 @@ package sun.rmi.server; import java.io.IOException; import java.io.ObjectInput; +import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.lang.reflect.Method; import java.rmi.MarshalException; @@ -38,6 +39,8 @@ import java.rmi.server.RemoteCall; import java.rmi.server.RemoteObject; import java.rmi.server.RemoteRef; import java.security.AccessController; + +import sun.misc.SharedSecrets; import sun.rmi.runtime.Log; import sun.rmi.transport.Connection; import sun.rmi.transport.LiveRef; @@ -318,6 +321,8 @@ public class UnicastRef implements RemoteRef { } else { throw new Error("Unrecognized primitive type: " + type); } + } else if (type == String.class && in instanceof ObjectInputStream) { + return SharedSecrets.getJavaObjectInputStreamReadString().readString((ObjectInputStream)in); } else { return in.readObject(); } diff --git a/src/share/classes/sun/rmi/transport/tcp/TCPEndpoint.java b/src/share/classes/sun/rmi/transport/tcp/TCPEndpoint.java index d7338219ace10206c81a579465f558940960f2bb..0d849ed7f293b84ba7775f0349da7cb9cf7fb09b 100644 --- a/src/share/classes/sun/rmi/transport/tcp/TCPEndpoint.java +++ b/src/share/classes/sun/rmi/transport/tcp/TCPEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, 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 @@ -29,6 +29,7 @@ import java.io.DataOutput; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; +import java.lang.reflect.Proxy; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; @@ -553,6 +554,9 @@ public class TCPEndpoint implements Endpoint { host = in.readUTF(); port = in.readInt(); csf = (RMIClientSocketFactory) in.readObject(); + if (Proxy.isProxyClass(csf.getClass())) { + throw new IOException("Invalid SocketFactory"); + } break; default: diff --git a/src/share/classes/sun/security/action/GetPropertyAction.java b/src/share/classes/sun/security/action/GetPropertyAction.java index 24ecc91a6166064065cf36a0df09fc032ef044b6..59bf32486d9bb99a98af0eb37401d5c713fe6181 100644 --- a/src/share/classes/sun/security/action/GetPropertyAction.java +++ b/src/share/classes/sun/security/action/GetPropertyAction.java @@ -108,4 +108,27 @@ public class GetPropertyAction implements PrivilegedAction { new GetPropertyAction(theProp)); } } + + /** + * Convenience method to get a property without going through doPrivileged + * if no security manager is present. This is unsafe for inclusion in a + * public API but allowable here since this class is now encapsulated. + * + * Note that this method performs a privileged action using caller-provided + * inputs. The caller of this method should take care to ensure that the + * inputs are not tainted and the returned property is not made accessible + * to untrusted code if it contains sensitive information. + * + * @param theProp the name of the system property. + * @param defaultVal the default value. + */ + public static String privilegedGetProperty(String theProp, + String defaultVal) { + if (System.getSecurityManager() == null) { + return System.getProperty(theProp, defaultVal); + } else { + return AccessController.doPrivileged( + new GetPropertyAction(theProp, defaultVal)); + } + } } diff --git a/src/share/classes/sun/security/jgss/krb5/CipherHelper.java b/src/share/classes/sun/security/jgss/krb5/CipherHelper.java index c637b0169d9d6f63cf6d3129d3c264e3090dea76..0b8adfb61159729f48d12c2a018e324309c97f6f 100644 --- a/src/share/classes/sun/security/jgss/krb5/CipherHelper.java +++ b/src/share/classes/sun/security/jgss/krb5/CipherHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2017, 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 @@ -44,6 +44,7 @@ import sun.security.krb5.internal.crypto.Des3; import sun.security.krb5.internal.crypto.Aes128; import sun.security.krb5.internal.crypto.Aes256; import sun.security.krb5.internal.crypto.ArcFourHmac; +import sun.security.krb5.internal.crypto.EType; class CipherHelper { @@ -77,10 +78,6 @@ class CipherHelper { private int sgnAlg, sealAlg; private byte[] keybytes; - // new token format from draft-ietf-krb-wg-gssapi-cfx-07 - // proto is used to determine new GSS token format for "newer" etypes - private int proto = 0; - CipherHelper(EncryptionKey key) throws GSSException { etype = key.getEType(); keybytes = key.getBytes(); @@ -106,7 +103,6 @@ class CipherHelper { case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: sgnAlg = -1; sealAlg = -1; - proto = 1; break; default: @@ -123,8 +119,10 @@ class CipherHelper { return sealAlg; } + // new token format from draft-ietf-krb-wg-gssapi-cfx-07 + // proto is used to determine new GSS token format for "newer" etypes int getProto() { - return proto; + return EType.isNewer(etype) ? 1 : 0; } int getEType() { diff --git a/src/share/classes/sun/security/jgss/krb5/InitSecContextToken.java b/src/share/classes/sun/security/jgss/krb5/InitSecContextToken.java index 0077e7edb2848cb0f60a26272e260d23104295d7..1688d5ceeca8df1f465b7e49269ac5371ca58df7 100644 --- a/src/share/classes/sun/security/jgss/krb5/InitSecContextToken.java +++ b/src/share/classes/sun/security/jgss/krb5/InitSecContextToken.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ -29,6 +29,8 @@ import com.sun.security.jgss.AuthorizationDataEntry; import org.ietf.jgss.*; import java.io.InputStream; import java.io.IOException; + +import sun.security.action.GetPropertyAction; import sun.security.krb5.*; import java.net.InetAddress; import sun.security.krb5.internal.AuthorizationData; @@ -36,6 +38,33 @@ import sun.security.krb5.internal.KerberosTime; class InitSecContextToken extends InitialToken { + // If non-mutual authentication is requested, there is no AP-REP message. + // The acceptor thus has no chance to send the seq-number field to the + // initiator. In this case, the initiator and acceptor should has an + // agreement to derive acceptor's initial seq-number if the acceptor wishes + // to send messages to the initiator. + + // If this flag is true, it will the same as the initiator's initial + // seq-number (as MIT krb5 and Windows SSPI do). Otherwise, it will be zero + // (as Heimdal does). The default value is true. + private static final boolean ACCEPTOR_USE_INITIATOR_SEQNUM; + + static { + // The ACCEPTOR_USE_INITIATOR_SEQNUM value is determined by the system + // property "sun.security.krb5.acceptor.sequence.number.nonmutual", + // which can be set to "initiator", "zero" or "0". + String propName = "sun.security.krb5.acceptor.sequence.number.nonmutual"; + String s = GetPropertyAction.privilegedGetProperty(propName, "initiator"); + if (s.equals("initiator")) { + ACCEPTOR_USE_INITIATOR_SEQNUM = true; + } else if (s.equals("zero") || s.equals("0")) { + ACCEPTOR_USE_INITIATOR_SEQNUM = false; + } else { + throw new AssertionError("Unrecognized value for " + propName + + ": " + s); + } + } + private KrbApReq apReq = null; /** @@ -79,7 +108,10 @@ class InitSecContextToken extends InitialToken { context.setKey(Krb5Context.SESSION_KEY, serviceTicket.getSessionKey()); if (!mutualRequired) - context.resetPeerSequenceNumber(0); + context.resetPeerSequenceNumber( + ACCEPTOR_USE_INITIATOR_SEQNUM + ? apReq.getSeqNumber().intValue() + : 0); } /** @@ -144,10 +176,12 @@ class InitSecContextToken extends InitialToken { apReqSeqNumber.intValue() : 0); context.resetPeerSequenceNumber(peerSeqNumber); - if (!context.getMutualAuthState()) - // Use the same sequence number as the peer - // (Behaviour exhibited by the Windows SSPI server) - context.resetMySequenceNumber(peerSeqNumber); + if (!context.getMutualAuthState()) { + context.resetMySequenceNumber( + ACCEPTOR_USE_INITIATOR_SEQNUM + ? peerSeqNumber + : 0); + } context.setAuthTime( new KerberosTime(apReq.getCreds().getAuthTime()).toString()); context.setTktFlags(apReq.getCreds().getFlags()); diff --git a/src/share/classes/sun/security/jgss/krb5/Krb5Context.java b/src/share/classes/sun/security/jgss/krb5/Krb5Context.java index a0658d0eacb10b4111d7260fd8de3f0712565d3a..e9ee13d442745003f85b862281247a359924b36c 100644 --- a/src/share/classes/sun/security/jgss/krb5/Krb5Context.java +++ b/src/share/classes/sun/security/jgss/krb5/Krb5Context.java @@ -713,14 +713,14 @@ class Krb5Context implements GSSContextSpi { if (subject != null && !subject.isReadOnly()) { /* - * Store the service credentials as - * javax.security.auth.kerberos.KerberosTicket in - * the Subject. We could wait till the context is - * succesfully established; however it is easier - * to do here and there is no harm indoing it here. - */ + * Store the service credentials as + * javax.security.auth.kerberos.KerberosTicket in + * the Subject. We could wait until the context is + * successfully established; however it is easier + * to do it here and there is no harm. + */ final KerberosTicket kt = - Krb5Util.credsToTicket(serviceCreds); + Krb5Util.credsToTicket(serviceCreds); AccessController.doPrivileged ( new java.security.PrivilegedAction() { public Void run() { diff --git a/src/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java b/src/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java index daefbbcbdab6777369d7697162392700007c9e4b..314cabb3c16aa82003705db34335cd21095d8b85 100644 --- a/src/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java +++ b/src/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java @@ -60,7 +60,9 @@ public class Krb5InitCredential private Krb5InitCredential(Krb5NameElement name, byte[] asn1Encoding, KerberosPrincipal client, + KerberosPrincipal clientAlias, KerberosPrincipal server, + KerberosPrincipal serverAlias, byte[] sessionKey, int keyType, boolean[] flags, @@ -81,14 +83,21 @@ public class Krb5InitCredential endTime, renewTill, clientAddresses); - + KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .kerberosTicketSetClientAlias(this, clientAlias); + KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .kerberosTicketSetServerAlias(this, serverAlias); this.name = name; try { // Cache this for later use by the sun.security.krb5 package. krb5Credentials = new Credentials(asn1Encoding, client.getName(), + (clientAlias != null ? + clientAlias.getName() : null), server.getName(), + (serverAlias != null ? + serverAlias.getName() : null), sessionKey, keyType, flags, @@ -111,7 +120,9 @@ public class Krb5InitCredential Credentials delegatedCred, byte[] asn1Encoding, KerberosPrincipal client, + KerberosPrincipal clientAlias, KerberosPrincipal server, + KerberosPrincipal serverAlias, byte[] sessionKey, int keyType, boolean[] flags, @@ -132,7 +143,10 @@ public class Krb5InitCredential endTime, renewTill, clientAddresses); - + KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .kerberosTicketSetClientAlias(this, clientAlias); + KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .kerberosTicketSetServerAlias(this, serverAlias); this.name = name; // A delegated cred does not have all fields set. So do not try to // creat new Credentials out of the delegatedCred. @@ -154,10 +168,18 @@ public class Krb5InitCredential Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL); } + KerberosPrincipal clientAlias = KerberosSecrets + .getJavaxSecurityAuthKerberosAccess() + .kerberosTicketGetClientAlias(tgt); + KerberosPrincipal serverAlias = KerberosSecrets + .getJavaxSecurityAuthKerberosAccess() + .kerberosTicketGetServerAlias(tgt); Krb5InitCredential result = new Krb5InitCredential(name, tgt.getEncoded(), tgt.getClient(), + clientAlias, tgt.getServer(), + serverAlias, tgt.getSessionKey().getEncoded(), tgt.getSessionKeyType(), tgt.getFlags(), @@ -183,10 +205,14 @@ public class Krb5InitCredential */ PrincipalName cPrinc = delegatedCred.getClient(); + PrincipalName cAPrinc = delegatedCred.getClientAlias(); PrincipalName sPrinc = delegatedCred.getServer(); + PrincipalName sAPrinc = delegatedCred.getServerAlias(); KerberosPrincipal client = null; + KerberosPrincipal clientAlias = null; KerberosPrincipal server = null; + KerberosPrincipal serverAlias = null; Krb5NameElement credName = null; @@ -197,6 +223,10 @@ public class Krb5InitCredential client = new KerberosPrincipal(fullName); } + if (cAPrinc != null) { + clientAlias = new KerberosPrincipal(cAPrinc.getName()); + } + // XXX Compare name to credName if (sPrinc != null) { @@ -205,11 +235,17 @@ public class Krb5InitCredential KerberosPrincipal.KRB_NT_SRV_INST); } + if (sAPrinc != null) { + serverAlias = new KerberosPrincipal(sAPrinc.getName()); + } + return new Krb5InitCredential(credName, delegatedCred, delegatedCred.getEncoded(), client, + clientAlias, server, + serverAlias, sessionKey.getBytes(), sessionKey.getEType(), delegatedCred.getFlags(), diff --git a/src/share/classes/sun/security/jgss/krb5/Krb5Util.java b/src/share/classes/sun/security/jgss/krb5/Krb5Util.java index 8f79df1e67df5094ec8d402ff8c2abdda3e2ada0..387edd76691fadeaee0f08f4776f1d91ec87c419 100644 --- a/src/share/classes/sun/security/jgss/krb5/Krb5Util.java +++ b/src/share/classes/sun/security/jgss/krb5/Krb5Util.java @@ -228,7 +228,7 @@ public class Krb5Util { public static KerberosTicket credsToTicket(Credentials serviceCreds) { EncryptionKey sessionKey = serviceCreds.getSessionKey(); - return new KerberosTicket( + KerberosTicket kt = new KerberosTicket( serviceCreds.getEncoded(), new KerberosPrincipal(serviceCreds.getClient().getName()), new KerberosPrincipal(serviceCreds.getServer().getName(), @@ -241,14 +241,35 @@ public class Krb5Util { serviceCreds.getEndTime(), serviceCreds.getRenewTill(), serviceCreds.getClientAddresses()); + PrincipalName clientAlias = serviceCreds.getClientAlias(); + PrincipalName serverAlias = serviceCreds.getServerAlias(); + if (clientAlias != null) { + KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .kerberosTicketSetClientAlias(kt, new KerberosPrincipal( + clientAlias.getName(), clientAlias.getNameType())); + } + if (serverAlias != null) { + KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .kerberosTicketSetServerAlias(kt, new KerberosPrincipal( + serverAlias.getName(), serverAlias.getNameType())); + } + return kt; }; public static Credentials ticketToCreds(KerberosTicket kerbTicket) throws KrbException, IOException { + KerberosPrincipal clientAlias = KerberosSecrets + .getJavaxSecurityAuthKerberosAccess() + .kerberosTicketGetClientAlias(kerbTicket); + KerberosPrincipal serverAlias = KerberosSecrets + .getJavaxSecurityAuthKerberosAccess() + .kerberosTicketGetServerAlias(kerbTicket); return new Credentials( kerbTicket.getEncoded(), kerbTicket.getClient().getName(), + (clientAlias != null ? clientAlias.getName() : null), kerbTicket.getServer().getName(), + (serverAlias != null ? serverAlias.getName() : null), kerbTicket.getSessionKey().getEncoded(), kerbTicket.getSessionKeyType(), kerbTicket.getFlags(), diff --git a/src/share/classes/sun/security/jgss/krb5/MessageToken_v2.java b/src/share/classes/sun/security/jgss/krb5/MessageToken_v2.java index 7d293ce5c4b8f6954a79aa857796f3a111bbb5ad..808c2014a94b16de85907e8370ae8bb662c51c51 100644 --- a/src/share/classes/sun/security/jgss/krb5/MessageToken_v2.java +++ b/src/share/classes/sun/security/jgss/krb5/MessageToken_v2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, 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 @@ -499,11 +499,11 @@ abstract class MessageToken_v2 extends Krb5Token { */ class MessageTokenHeader { - private int tokenId; - private byte[] bytes = new byte[TOKEN_HEADER_SIZE]; + private int tokenId; + private byte[] bytes = new byte[TOKEN_HEADER_SIZE]; - // Writes a new token header - public MessageTokenHeader(int tokenId, boolean conf) throws GSSException { + // Writes a new token header + public MessageTokenHeader(int tokenId, boolean conf) throws GSSException { this.tokenId = tokenId; @@ -609,7 +609,7 @@ abstract class MessageToken_v2 extends Krb5Token { prop.setQOP(0); // sequence number - seqNumber = readBigEndian(bytes, 0, 8); + seqNumber = readBigEndian(bytes, 12, 4); } /** diff --git a/src/share/classes/sun/security/jgss/krb5/SubjectComber.java b/src/share/classes/sun/security/jgss/krb5/SubjectComber.java index a7100f07c94360b242704529558b774b6526ba3e..1bc1bf7d62973adb1c963709f225aeb02e163d0b 100644 --- a/src/share/classes/sun/security/jgss/krb5/SubjectComber.java +++ b/src/share/classes/sun/security/jgss/krb5/SubjectComber.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, 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 @@ -25,6 +25,8 @@ package sun.security.jgss.krb5; +import sun.security.krb5.KerberosSecrets; + import javax.security.auth.kerberos.KerberosTicket; import javax.security.auth.kerberos.KerberosKey; import javax.security.auth.Subject; @@ -182,24 +184,45 @@ class SubjectComber { } } else { + KerberosPrincipal serverAlias = KerberosSecrets + .getJavaxSecurityAuthKerberosAccess() + .kerberosTicketGetServerAlias(ticket); if (serverPrincipal == null || - ticket.getServer().getName().equals(serverPrincipal)) { - + ticket.getServer().getName().equals(serverPrincipal) || + (serverAlias != null && + serverPrincipal.equals( + serverAlias.getName()))) { + KerberosPrincipal clientAlias = KerberosSecrets + .getJavaxSecurityAuthKerberosAccess() + .kerberosTicketGetClientAlias(ticket); if (clientPrincipal == null || clientPrincipal.equals( - ticket.getClient().getName())) { + ticket.getClient().getName()) || + (clientAlias != null && + clientPrincipal.equals( + clientAlias.getName()))) { if (oneOnly) { return ticket; } else { // Record names so that tickets will // all belong to same principals if (clientPrincipal == null) { - clientPrincipal = - ticket.getClient().getName(); + if (clientAlias == null) { + clientPrincipal = + ticket.getClient().getName(); + } else { + clientPrincipal = + clientAlias.getName(); + } } if (serverPrincipal == null) { - serverPrincipal = - ticket.getServer().getName(); + if (serverAlias == null) { + serverPrincipal = + ticket.getServer().getName(); + } else { + serverPrincipal = + serverAlias.getName(); + } } answer.add(credClass.cast(ticket)); } diff --git a/src/share/classes/sun/security/krb5/Checksum.java b/src/share/classes/sun/security/krb5/Checksum.java index 6a7f491257d8e70d3960200b745780bb0d028fae..92a5de8d58cdd84352a5b9a3badc6ae33ac00d37 100644 --- a/src/share/classes/sun/security/krb5/Checksum.java +++ b/src/share/classes/sun/security/krb5/Checksum.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -69,6 +69,7 @@ public class Checksum { // draft-brezak-win2k-krb-rc4-hmac-04.txt public static final int CKSUMTYPE_HMAC_MD5_ARCFOUR = -138; + // default checksum type, -1 if not set static int CKSUMTYPE_DEFAULT; static int SAFECKSUMTYPE_DEFAULT; @@ -83,26 +84,19 @@ public class Checksum { try { cfg = Config.getInstance(); temp = cfg.get("libdefaults", "default_checksum"); - if (temp != null) - { - CKSUMTYPE_DEFAULT = Config.getType(temp); - } else { - /* - * If the default checksum is not - * specified in the configuration we - * set it to RSA_MD5. We follow the MIT and - * SEAM implementation. - */ - CKSUMTYPE_DEFAULT = CKSUMTYPE_RSA_MD5; - } + if (temp != null) { + CKSUMTYPE_DEFAULT = Config.getType(temp); + } else { + CKSUMTYPE_DEFAULT = -1; + } } catch (Exception exc) { if (DEBUG) { System.out.println("Exception in getting default checksum "+ - "value from the configuration " + - "Setting default checksum to be RSA-MD5"); + "value from the configuration. " + + "No default checksum set."); exc.printStackTrace(); } - CKSUMTYPE_DEFAULT = CKSUMTYPE_RSA_MD5; + CKSUMTYPE_DEFAULT = -1; } @@ -112,97 +106,100 @@ public class Checksum { { SAFECKSUMTYPE_DEFAULT = Config.getType(temp); } else { - SAFECKSUMTYPE_DEFAULT = CKSUMTYPE_RSA_MD5_DES; + SAFECKSUMTYPE_DEFAULT = -1; } } catch (Exception exc) { if (DEBUG) { System.out.println("Exception in getting safe default " + "checksum value " + - "from the configuration Setting " + - "safe default checksum to be RSA-MD5"); + "from the configuration Setting. " + + "No safe default checksum set."); exc.printStackTrace(); } - SAFECKSUMTYPE_DEFAULT = CKSUMTYPE_RSA_MD5_DES; + SAFECKSUMTYPE_DEFAULT = -1; } } /** * Constructs a new Checksum using the raw data and type. + * + * This constructor is only used by Authenticator Checksum + * {@link sun.security.jgss.krb5.InitialToken.OverloadedChecksum} + * where the checksum type must be 0x8003 + * (see https://tools.ietf.org/html/rfc4121#section-4.1.1) + * and checksum field/value is used to convey service flags, + * channel bindings, and optional delegation information. + * This special type does NOT have a {@link CksumType} and has its + * own calculating and verification rules. It does has the same + * ASN.1 encoding though. + * * @data the byte array of checksum. * @new_cksumType the type of checksum. - * */ - // used in InitialToken public Checksum(byte[] data, int new_cksumType) { cksumType = new_cksumType; checksum = data; } /** - * Constructs a new Checksum by calculating the checksum over the data - * using specified checksum type. - * @new_cksumType the type of checksum. - * @data the data that needs to be performed a checksum calculation on. + * Constructs a new Checksum by calculating over the data using + * the specified checksum type. If the checksum is unkeyed, key + * and usage are ignored. + * + * @param new_cksumType the type of checksum. If set to -1, the + * {@linkplain EType#checksumType() mandatory checksum type} + * for the encryption type of {@code key} will be used + * @param data the data that needs to be performed a checksum calculation on + * @param key the key used by a keyed checksum + * @param usage the usage used by a keyed checksum */ - public Checksum(int new_cksumType, byte[] data) - throws KdcErrException, KrbCryptoException { - - cksumType = new_cksumType; - CksumType cksumEngine = CksumType.getInstance(cksumType); - if (!cksumEngine.isSafe()) { - checksum = cksumEngine.calculateChecksum(data, data.length); + public Checksum(int new_cksumType, byte[] data, + EncryptionKey key, int usage) + throws KdcErrException, KrbApErrException, KrbCryptoException { + if (new_cksumType == -1) { + cksumType = EType.getInstance(key.getEType()).checksumType(); } else { - throw new KdcErrException(Krb5.KRB_AP_ERR_INAPP_CKSUM); + cksumType = new_cksumType; } + checksum = CksumType.getInstance(cksumType).calculateChecksum( + data, data.length, key.getBytes(), usage); } /** - * Constructs a new Checksum by calculating the keyed checksum - * over the data using specified checksum type. - * @new_cksumType the type of checksum. - * @data the data that needs to be performed a checksum calculation on. + * Verifies the keyed checksum over the data passed in. */ - // KrbSafe, KrbTgsReq - public Checksum(int new_cksumType, byte[] data, - EncryptionKey key, int usage) - throws KdcErrException, KrbApErrException, KrbCryptoException { - cksumType = new_cksumType; + public boolean verifyKeyedChecksum(byte[] data, EncryptionKey key, int usage) + throws KdcErrException, KrbApErrException, KrbCryptoException { CksumType cksumEngine = CksumType.getInstance(cksumType); - if (!cksumEngine.isSafe()) + if (!cksumEngine.isKeyed()) { throw new KrbApErrException(Krb5.KRB_AP_ERR_INAPP_CKSUM); - checksum = - cksumEngine.calculateKeyedChecksum(data, - data.length, - key.getBytes(), - usage); + } else { + return cksumEngine.verifyChecksum( + data, data.length, key.getBytes(), checksum, usage); + } } + /** - * Verifies the keyed checksum over the data passed in. + * Verifies the checksum over the data passed in. The checksum might + * be a keyed or not. + * + * =============== ATTENTION! Use with care ================== + * According to https://tools.ietf.org/html/rfc3961#section-6.1, + * An unkeyed checksum should only be used "in limited circumstances + * where the lack of a key does not provide a window for an attack, + * preferably as part of an encrypted message". */ - public boolean verifyKeyedChecksum(byte[] data, EncryptionKey key, - int usage) - throws KdcErrException, KrbApErrException, KrbCryptoException { - CksumType cksumEngine = CksumType.getInstance(cksumType); - if (!cksumEngine.isSafe()) - throw new KrbApErrException(Krb5.KRB_AP_ERR_INAPP_CKSUM); - return cksumEngine.verifyKeyedChecksum(data, - data.length, - key.getBytes(), - checksum, - usage); + public boolean verifyAnyChecksum(byte[] data, EncryptionKey key, int usage) + throws KdcErrException, KrbCryptoException { + return CksumType.getInstance(cksumType).verifyChecksum( + data, data.length, key.getBytes(), checksum, usage); } - /* - public Checksum(byte[] data) throws KdcErrException, KrbCryptoException { - this(Checksum.CKSUMTYPE_DEFAULT, data); - } - */ - boolean isEqual(Checksum cksum) throws KdcErrException { - if (cksumType != cksum.cksumType) + if (cksumType != cksum.cksumType) { return false; - CksumType cksumEngine = CksumType.getInstance(cksumType); + } return CksumType.isChecksumEqual(checksum, cksum.checksum); } @@ -214,7 +211,7 @@ public class Checksum { * @exception IOException if an I/O error occurs while reading encoded data. * */ - private Checksum(DerValue encoding) throws Asn1Exception, IOException { + public Checksum(DerValue encoding) throws Asn1Exception, IOException { DerValue der; if (encoding.getTag() != DerValue.tag_Sequence) { throw new Asn1Exception(Krb5.ASN1_BAD_ID); diff --git a/src/share/classes/sun/security/krb5/Config.java b/src/share/classes/sun/security/krb5/Config.java index 7ee9231b0f9efcf84805040c95cb9bfc574b9e4c..fe6565cbab697e8541026faeec91eb4dd798dbbe 100644 --- a/src/share/classes/sun/security/krb5/Config.java +++ b/src/share/classes/sun/security/krb5/Config.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -30,25 +30,24 @@ */ package sun.security.krb5; -import java.io.File; -import java.io.FileInputStream; -import java.util.Hashtable; -import java.util.Vector; -import java.util.ArrayList; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.IOException; -import java.util.StringTokenizer; +import java.io.*; import java.net.InetAddress; import java.net.UnknownHostException; import java.security.AccessController; import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Hashtable; import java.util.List; import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import sun.net.dns.ResolverConfiguration; import sun.security.krb5.internal.crypto.EType; import sun.security.krb5.internal.Krb5; +import sun.security.util.SecurityProperties; /** * This class maintains key-value pairs of Kerberos configurable constants @@ -57,6 +56,41 @@ import sun.security.krb5.internal.Krb5; public class Config { + /** + * {@systemProperty sun.security.krb5.disableReferrals} property + * indicating whether or not cross-realm referrals (RFC 6806) are + * enabled. + */ + public static final boolean DISABLE_REFERRALS; + + /** + * {@systemProperty sun.security.krb5.maxReferrals} property + * indicating the maximum number of cross-realm referral + * hops allowed. + */ + public static final int MAX_REFERRALS; + + static { + String disableReferralsProp = + SecurityProperties.privilegedGetOverridable( + "sun.security.krb5.disableReferrals"); + if (disableReferralsProp != null) { + DISABLE_REFERRALS = "true".equalsIgnoreCase(disableReferralsProp); + } else { + DISABLE_REFERRALS = false; + } + + int maxReferralsValue = 5; + String maxReferralsProp = + SecurityProperties.privilegedGetOverridable( + "sun.security.krb5.maxReferrals"); + try { + maxReferralsValue = Integer.parseInt(maxReferralsProp); + } catch (NumberFormatException e) { + } + MAX_REFERRALS = maxReferralsValue; + } + /* * Only allow a single instance of Config. */ @@ -257,7 +291,11 @@ public class Config { } /** - * Gets all values for the specified keys. + * Gets all values (at least one) for the specified keys separated by + * a whitespace, or null if there is no such keys. + * The values can either be provided on a single line, or on multiple lines + * using the same key. When provided on a single line, the value can be + * comma or space separated. * @throws IllegalArgumentException if any of the keys is illegal * (See {@link #get}) */ @@ -267,6 +305,7 @@ public class Config { StringBuilder sb = new StringBuilder(); boolean first = true; for (String s: v) { + s = s.replaceAll("[\\s,]+", " "); if (first) { sb.append(s); first = false; @@ -313,6 +352,72 @@ public class Config { } } + /** + * Translates a duration value into seconds. + * + * The format can be one of "h:m[:s]", "NdNhNmNs", and "N". See + * http://web.mit.edu/kerberos/krb5-devel/doc/basic/date_format.html#duration + * for definitions. + * + * @param s the string duration + * @return time in seconds + * @throw KrbException if format is illegal + */ + public static int duration(String s) throws KrbException { + + if (s.isEmpty()) { + throw new KrbException("Duration cannot be empty"); + } + + // N + if (s.matches("\\d+")) { + return Integer.parseInt(s); + } + + // h:m[:s] + Matcher m = Pattern.compile("(\\d+):(\\d+)(:(\\d+))?").matcher(s); + if (m.matches()) { + int hr = Integer.parseInt(m.group(1)); + int min = Integer.parseInt(m.group(2)); + if (min >= 60) { + throw new KrbException("Illegal duration format " + s); + } + int result = hr * 3600 + min * 60; + if (m.group(4) != null) { + int sec = Integer.parseInt(m.group(4)); + if (sec >= 60) { + throw new KrbException("Illegal duration format " + s); + } + result += sec; + } + return result; + } + + // NdNhNmNs + // 120m allowed. Maybe 1h120m is not good, but still allowed + m = Pattern.compile( + "((\\d+)d)?\\s*((\\d+)h)?\\s*((\\d+)m)?\\s*((\\d+)s)?", + Pattern.CASE_INSENSITIVE).matcher(s); + if (m.matches()) { + int result = 0; + if (m.group(2) != null) { + result += 86400 * Integer.parseInt(m.group(2)); + } + if (m.group(4) != null) { + result += 3600 * Integer.parseInt(m.group(4)); + } + if (m.group(6) != null) { + result += 60 * Integer.parseInt(m.group(6)); + } + if (m.group(8) != null) { + result += Integer.parseInt(m.group(8)); + } + return result; + } + + throw new KrbException("Illegal duration format " + s); + } + /** * Gets the int value for the specified keys. * @param keys the keys diff --git a/src/share/classes/sun/security/krb5/Credentials.java b/src/share/classes/sun/security/krb5/Credentials.java index 3fe29530717811791e727cfe86aee0c8204862fd..b364a628e957d3740a9f6b7635cd699a8476dda3 100644 --- a/src/share/classes/sun/security/krb5/Credentials.java +++ b/src/share/classes/sun/security/krb5/Credentials.java @@ -48,7 +48,9 @@ public class Credentials { Ticket ticket; PrincipalName client; + PrincipalName clientAlias; PrincipalName server; + PrincipalName serverAlias; EncryptionKey key; TicketFlags flags; KerberosTime authTime; @@ -78,7 +80,9 @@ public class Credentials { public Credentials(Ticket new_ticket, PrincipalName new_client, + PrincipalName new_client_alias, PrincipalName new_server, + PrincipalName new_server_alias, EncryptionKey new_key, TicketFlags new_flags, KerberosTime authTime, @@ -87,14 +91,17 @@ public class Credentials { KerberosTime renewTill, HostAddresses cAddr, AuthorizationData authzData) { - this(new_ticket, new_client, new_server, new_key, new_flags, - authTime, new_startTime, new_endTime, renewTill, cAddr); + this(new_ticket, new_client, new_client_alias, new_server, + new_server_alias, new_key, new_flags, authTime, + new_startTime, new_endTime, renewTill, cAddr); this.authzData = authzData; } public Credentials(Ticket new_ticket, PrincipalName new_client, + PrincipalName new_client_alias, PrincipalName new_server, + PrincipalName new_server_alias, EncryptionKey new_key, TicketFlags new_flags, KerberosTime authTime, @@ -104,7 +111,9 @@ public class Credentials { HostAddresses cAddr) { ticket = new_ticket; client = new_client; + clientAlias = new_client_alias; server = new_server; + serverAlias = new_server_alias; key = new_key; flags = new_flags; this.authTime = authTime; @@ -116,7 +125,9 @@ public class Credentials { public Credentials(byte[] encoding, String client, + String clientAlias, String server, + String serverAlias, byte[] keyBytes, int keyType, boolean[] flags, @@ -127,7 +138,11 @@ public class Credentials { InetAddress[] cAddrs) throws KrbException, IOException { this(new Ticket(encoding), new PrincipalName(client, PrincipalName.KRB_NT_PRINCIPAL), + (clientAlias == null? null : new PrincipalName(clientAlias, + PrincipalName.KRB_NT_PRINCIPAL)), new PrincipalName(server, PrincipalName.KRB_NT_SRV_INST), + (serverAlias == null? null : new PrincipalName(serverAlias, + PrincipalName.KRB_NT_SRV_INST)), new EncryptionKey(keyType, keyBytes), (flags == null? null: new TicketFlags(flags)), (authTime == null? null: new KerberosTime(authTime)), @@ -152,10 +167,18 @@ public class Credentials { return client; } + public final PrincipalName getClientAlias() { + return clientAlias; + } + public final PrincipalName getServer() { return server; } + public final PrincipalName getServerAlias() { + return serverAlias; + } + public final EncryptionKey getSessionKey() { return key; } @@ -271,6 +294,7 @@ public class Credentials { return new KrbTgsReq(options, this, server, + serverAlias, null, // from null, // till null, // rtime @@ -488,7 +512,11 @@ public class Credentials { public static void printDebug(Credentials c) { System.out.println(">>> DEBUG: ----Credentials----"); System.out.println("\tclient: " + c.client.toString()); + if (c.clientAlias != null) + System.out.println("\tclient alias: " + c.clientAlias.toString()); System.out.println("\tserver: " + c.server.toString()); + if (c.serverAlias != null) + System.out.println("\tserver alias: " + c.serverAlias.toString()); System.out.println("\tticket: sname: " + c.ticket.sname.toString()); if (c.startTime != null) { System.out.println("\tstartTime: " + c.startTime.getTime()); @@ -516,7 +544,11 @@ public class Credentials { public String toString() { StringBuffer buffer = new StringBuffer("Credentials:"); buffer.append( "\n client=").append(client); + if (clientAlias != null) + buffer.append( "\n clientAlias=").append(clientAlias); buffer.append( "\n server=").append(server); + if (serverAlias != null) + buffer.append( "\n serverAlias=").append(serverAlias); if (authTime != null) { buffer.append("\n authTime=").append(authTime); } @@ -531,4 +563,23 @@ public class Credentials { return buffer.toString(); } + public sun.security.krb5.internal.ccache.Credentials toCCacheCreds() { + return new sun.security.krb5.internal.ccache.Credentials( + getClient(), getServer(), + getSessionKey(), + date2kt(getAuthTime()), + date2kt(getStartTime()), + date2kt(getEndTime()), + date2kt(getRenewTill()), + false, + flags, + new HostAddresses(getClientAddresses()), + getAuthzData(), + getTicket(), + null); + } + + private static KerberosTime date2kt(Date d) { + return d == null ? null : new KerberosTime(d); + } } diff --git a/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java b/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java index 84ca79bc9b3ba01d8764d49a8a346d4eb4e70460..7d1ebd484cf5adcf43a03d77600bb2125b2770cd 100644 --- a/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java +++ b/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java @@ -25,6 +25,7 @@ package sun.security.krb5; +import javax.security.auth.kerberos.KerberosPrincipal; import javax.security.auth.kerberos.KerberosTicket; import javax.security.auth.kerberos.KeyTab; @@ -39,6 +40,14 @@ public interface JavaxSecurityAuthKerberosAccess { public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot( KeyTab ktab); + public KerberosPrincipal kerberosTicketGetClientAlias(KerberosTicket t); + + public void kerberosTicketSetClientAlias(KerberosTicket t, KerberosPrincipal a); + + public KerberosPrincipal kerberosTicketGetServerAlias(KerberosTicket t); + + public void kerberosTicketSetServerAlias(KerberosTicket t, KerberosPrincipal a); + /** * Returns the proxy for a KerberosTicket. */ diff --git a/src/share/classes/sun/security/krb5/KrbApReq.java b/src/share/classes/sun/security/krb5/KrbApReq.java index fbd05574f46ca318c61503183835b92283b3bf12..e36aeac4d60722e91c481cef694b404d61bb4cbf 100644 --- a/src/share/classes/sun/security/krb5/KrbApReq.java +++ b/src/share/classes/sun/security/krb5/KrbApReq.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -361,7 +361,9 @@ public class KrbApReq { creds = new Credentials( apReqMessg.ticket, authenticator.cname, + null, apReqMessg.ticket.sname, + null, enc_ticketPart.key, enc_ticketPart.flags, enc_ticketPart.authtime, diff --git a/src/share/classes/sun/security/krb5/KrbAsRep.java b/src/share/classes/sun/security/krb5/KrbAsRep.java index b03276fd09e4d1ac6c566d6d3b9388a356085145..202e86c2bfafe2b0528abc24e0e8be289b39199d 100644 --- a/src/share/classes/sun/security/krb5/KrbAsRep.java +++ b/src/share/classes/sun/security/krb5/KrbAsRep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -118,7 +118,7 @@ class KrbAsRep extends KrbKdcRep { "Cannot find key for type/kvno to decrypt AS REP - " + EType.toString(encPartKeyType) + "/" + encPartKvno); } - decrypt(dkey, asReq); + decrypt(dkey, asReq, cname); } /** @@ -136,7 +136,7 @@ class KrbAsRep extends KrbKdcRep { password, encPartKeyType, PAData.getSaltAndParams(encPartKeyType, rep.pAData)); - decrypt(dkey, asReq); + decrypt(dkey, asReq, cname); } /** @@ -144,7 +144,8 @@ class KrbAsRep extends KrbKdcRep { * @param dkey the decryption key to use * @param asReq the original AS-REQ sent, used to validate AS-REP */ - private void decrypt(EncryptionKey dkey, KrbAsReq asReq) + private void decrypt(EncryptionKey dkey, KrbAsReq asReq, + PrincipalName cname) throws KrbException, Asn1Exception, IOException { byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey, KeyUsage.KU_ENC_AS_REP_PART); @@ -155,12 +156,18 @@ class KrbAsRep extends KrbKdcRep { rep.encKDCRepPart = enc_part; ASReq req = asReq.getMessage(); - check(true, req, rep); + check(true, req, rep, dkey); + + PrincipalName clientAlias = cname; + if (clientAlias.equals(rep.cname)) + clientAlias = null; creds = new Credentials( rep.ticket, - req.reqBody.cname, + rep.cname, + clientAlias, enc_part.sname, + null, // No server alias expected in a TGT enc_part.key, enc_part.flags, enc_part.authtime, diff --git a/src/share/classes/sun/security/krb5/KrbAsReq.java b/src/share/classes/sun/security/krb5/KrbAsReq.java index 8de29b346ae1a741bce16243162271e184185c68..19e3ef61076237894fdb8e6e46791d8c363d1e3a 100644 --- a/src/share/classes/sun/security/krb5/KrbAsReq.java +++ b/src/share/classes/sun/security/krb5/KrbAsReq.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -35,6 +35,8 @@ import sun.security.krb5.internal.*; import sun.security.krb5.internal.crypto.Nonce; import sun.security.krb5.internal.crypto.KeyUsage; import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; /** * This class encapsulates the KRB-AS-REQ message that the client @@ -57,14 +59,14 @@ public class KrbAsReq { KerberosTime till, // ok, will use KerberosTime rtime, // ok int[] eTypes, // NO - HostAddresses addresses // ok + HostAddresses addresses, // ok + PAData[] extraPAs // ok ) throws KrbException, IOException { if (options == null) { options = new KDCOptions(); } - // check if they are valid arguments. The optional fields should be // consistent with settings in KDCOptions. Mar 17 2000 if (options.get(KDCOptions.FORWARDED) || @@ -82,12 +84,6 @@ public class KrbAsReq { } else { if (from != null) from = null; } - if (options.get(KDCOptions.RENEWABLE)) { - // if (rtime == null) - // throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); - } else { - if (rtime != null) rtime = null; - } PAData[] paData = null; if (pakey != null) { @@ -99,6 +95,15 @@ public class KrbAsReq { paData[0] = new PAData( Krb5.PA_ENC_TIMESTAMP, encTs.asn1Encode()); } + if (extraPAs != null && extraPAs.length > 0) { + if (paData == null) { + paData = new PAData[extraPAs.length]; + } else { + paData = Arrays.copyOf(paData, paData.length + extraPAs.length); + } + System.arraycopy(extraPAs, 0, paData, + paData.length - extraPAs.length, extraPAs.length); + } if (cname.getRealm() == null) { throw new RealmException(Krb5.REALM_NULL, @@ -109,8 +114,10 @@ public class KrbAsReq { System.out.println(">>> KrbAsReq creating message"); } + Config cfg = Config.getInstance(); + // check to use addresses in tickets - if (addresses == null && Config.getInstance().useAddresses()) { + if (addresses == null && cfg.useAddresses()) { addresses = HostAddresses.getLocalAddresses(); } @@ -120,7 +127,26 @@ public class KrbAsReq { } if (till == null) { - till = new KerberosTime(0); // Choose KDC maximum allowed + String d = cfg.get("libdefaults", "ticket_lifetime"); + if (d != null) { + till = new KerberosTime(Instant.now().plusSeconds(Config.duration(d))); + } else { + till = new KerberosTime(0); // Choose KDC maximum allowed + } + } + + if (rtime == null) { + String d = cfg.get("libdefaults", "renew_lifetime"); + if (d != null) { + rtime = new KerberosTime(Instant.now().plusSeconds(Config.duration(d))); + } + } + + if (rtime != null) { + options.set(KDCOptions.RENEWABLE, true); + if (till.greaterThan(rtime)) { + rtime = till; + } } // enc-authorization-data and additional-tickets never in AS-REQ diff --git a/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java b/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java index 3c8fb904017d2a9a7f46ecdbad91763b6b7b68a5..445fa19dfbaa93e9428a930677422671f6763668 100644 --- a/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java +++ b/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2019, 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 @@ -68,6 +68,7 @@ public final class KrbAsReqBuilder { // Common data for AS-REQ fields private KDCOptions options; private PrincipalName cname; + private PrincipalName refCname; // May be changed by referrals private PrincipalName sname; private KerberosTime from; private KerberosTime till; @@ -100,6 +101,7 @@ public final class KrbAsReqBuilder { private void init(PrincipalName cname) throws KrbException { this.cname = cname; + this.refCname = cname; state = State.INIT; } @@ -224,6 +226,16 @@ public final class KrbAsReqBuilder { this.options = options; } + public void setTill(KerberosTime till) { + checkState(State.INIT, "Cannot specify till"); + this.till = till; + } + + public void setRTime(KerberosTime rtime) { + checkState(State.INIT, "Cannot specify rtime"); + this.rtime = rtime; + } + /** * Sets or clears target. If cleared, KrbAsReq might choose krbtgt * for cname realm @@ -252,7 +264,9 @@ public final class KrbAsReqBuilder { * @throws KrbException * @throws IOException */ - private KrbAsReq build(EncryptionKey key) throws KrbException, IOException { + private KrbAsReq build(EncryptionKey key, ReferralsState referralsState) + throws KrbException, IOException { + PAData[] extraPAs = null; int[] eTypes; if (password != null) { eTypes = EType.getDefaults("default_tkt_enctypes"); @@ -262,15 +276,24 @@ public final class KrbAsReqBuilder { ks); for (EncryptionKey k: ks) k.destroy(); } + options = (options == null) ? new KDCOptions() : options; + if (referralsState.isEnabled()) { + options.set(KDCOptions.CANONICALIZE, true); + extraPAs = new PAData[]{ new PAData(Krb5.PA_REQ_ENC_PA_REP, + new byte[]{}) }; + } else { + options.set(KDCOptions.CANONICALIZE, false); + } return new KrbAsReq(key, options, - cname, + refCname, sname, from, till, rtime, eTypes, - addresses); + addresses, + extraPAs); } /** @@ -308,11 +331,15 @@ public final class KrbAsReqBuilder { */ private KrbAsReqBuilder send() throws KrbException, IOException { boolean preAuthFailedOnce = false; - KdcComm comm = new KdcComm(cname.getRealmAsString()); + KdcComm comm = null; EncryptionKey pakey = null; + ReferralsState referralsState = new ReferralsState(); while (true) { + if (referralsState.refreshComm()) { + comm = new KdcComm(refCname.getRealmAsString()); + } try { - req = build(pakey); + req = build(pakey, referralsState); rep = new KrbAsRep(comm.send(req.encoding())); return this; } catch (KrbException ke) { @@ -341,12 +368,71 @@ public final class KrbAsReqBuilder { } paList = kerr.getPA(); // Update current paList } else { + if (referralsState.handleError(ke)) { + pakey = null; + preAuthFailedOnce = false; + continue; + } throw ke; } } } } + private final class ReferralsState { + private boolean enabled; + private int count; + private boolean refreshComm; + + ReferralsState() throws KrbException { + if (Config.DISABLE_REFERRALS) { + if (refCname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) { + throw new KrbException("NT-ENTERPRISE principals only allowed" + + " when referrals are enabled."); + } + enabled = false; + } else { + enabled = true; + } + refreshComm = true; + } + + boolean handleError(KrbException ke) throws RealmException { + if (enabled) { + if (ke.returnCode() == Krb5.KRB_ERR_WRONG_REALM) { + Realm referredRealm = ke.getError().getClientRealm(); + if (req.getMessage().reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) && + referredRealm != null && referredRealm.toString().length() > 0 && + count < Config.MAX_REFERRALS) { + refCname = new PrincipalName(refCname.getNameType(), + refCname.getNameStrings(), referredRealm); + refreshComm = true; + count++; + return true; + } + } + if (count < Config.MAX_REFERRALS && + refCname.getNameType() != PrincipalName.KRB_NT_ENTERPRISE) { + // Server may raise an error if CANONICALIZE is true. + // Try CANONICALIZE false. + enabled = false; + return true; + } + } + return false; + } + + boolean refreshComm() { + boolean retRefreshComm = refreshComm; + refreshComm = false; + return retRefreshComm; + } + + boolean isEnabled() { + return enabled; + } + } + /** * Performs AS-REQ send and AS-REP receive. * Maybe a state is needed here, to divide prepare process and getCreds. diff --git a/src/share/classes/sun/security/krb5/KrbCred.java b/src/share/classes/sun/security/krb5/KrbCred.java index e6a4785818fd2facdec4cadbfdd36b3e9cf6d0d5..0ce26efc4a972a6fd1d0ef7c0c5dbd046f1422e0 100644 --- a/src/share/classes/sun/security/krb5/KrbCred.java +++ b/src/share/classes/sun/security/krb5/KrbCred.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -34,6 +34,7 @@ package sun.security.krb5; import sun.security.krb5.internal.*; import sun.security.krb5.internal.crypto.KeyUsage; import java.io.IOException; + import sun.security.util.DerValue; /** @@ -62,7 +63,6 @@ public class KrbCred { PrincipalName client = tgt.getClient(); PrincipalName tgService = tgt.getServer(); - PrincipalName server = serviceTicket.getServer(); if (!serviceTicket.getClient().equals(client)) throw new KrbException(Krb5.KRB_ERR_GENERIC, "Client principal does not match"); @@ -75,14 +75,10 @@ public class KrbCred { options.set(KDCOptions.FORWARDED, true); options.set(KDCOptions.FORWARDABLE, true); - HostAddresses sAddrs = null; - // XXX Also NT_GSS_KRB5_PRINCIPAL can be a host based principal - // GSSName.NT_HOSTBASED_SERVICE should display with KRB_NT_SRV_HST - if (server.getNameType() == PrincipalName.KRB_NT_SRV_HST) - sAddrs= new HostAddresses(server); - KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService, - null, null, null, null, sAddrs, null, null, null); + null, null, null, null, null, + null, // No easy way to get addresses right + null, null, null); credMessg = createMessage(tgsReq.sendAndGetCreds(), key); obuf = credMessg.asn1Encode(); @@ -94,7 +90,6 @@ public class KrbCred { EncryptionKey sessionKey = delegatedCreds.getSessionKey(); PrincipalName princ = delegatedCreds.getClient(); - Realm realm = princ.getRealm(); PrincipalName tgService = delegatedCreds.getServer(); KrbCredInfo credInfo = new KrbCredInfo(sessionKey, @@ -157,7 +152,7 @@ public class KrbCred { + " endtime=" + endtime + "renewTill=" + renewTill); } - creds = new Credentials(ticket, pname, sname, credInfoKey, + creds = new Credentials(ticket, pname, null, sname, null, credInfoKey, flags, authtime, starttime, endtime, renewTill, caddr); } diff --git a/src/share/classes/sun/security/krb5/KrbKdcRep.java b/src/share/classes/sun/security/krb5/KrbKdcRep.java index 6d79afe222cccbea7e06fd6f18e1f07532398c1e..da4a8fa400321e0ab1814effcdb78efed7db8409 100644 --- a/src/share/classes/sun/security/krb5/KrbKdcRep.java +++ b/src/share/classes/sun/security/krb5/KrbKdcRep.java @@ -31,23 +31,41 @@ package sun.security.krb5; import sun.security.krb5.internal.*; +import sun.security.krb5.internal.crypto.KeyUsage; +import sun.security.util.DerInputStream; abstract class KrbKdcRep { static void check( boolean isAsReq, KDCReq req, - KDCRep rep + KDCRep rep, + EncryptionKey replyKey ) throws KrbApErrException { - if (isAsReq && !req.reqBody.cname.equals(rep.cname)) { + // cname change in AS-REP is allowed only if the client + // sent CANONICALIZE and the server supports RFC 6806 - Section 11 + // FAST scheme (ENC-PA-REP flag). + if (isAsReq && !req.reqBody.cname.equals(rep.cname) && + (!req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) || + !rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP))) { rep.encKDCRepPart.key.destroy(); throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } + // sname change in TGS-REP is allowed only if client + // sent CANONICALIZE and new sname is a referral of + // the form krbtgt/TO-REALM.COM@FROM-REALM.COM. if (!req.reqBody.sname.equals(rep.encKDCRepPart.sname)) { - rep.encKDCRepPart.key.destroy(); - throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); + String[] snameStrings = rep.encKDCRepPart.sname.getNameStrings(); + if (isAsReq || !req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) || + snameStrings == null || snameStrings.length != 2 || + !snameStrings[0].equals(PrincipalName.TGS_DEFAULT_SRV_NAME) || + !rep.encKDCRepPart.sname.getRealmString().equals( + req.reqBody.sname.getRealmString())) { + rep.encKDCRepPart.key.destroy(); + throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); + } } if (req.reqBody.getNonce() != rep.encKDCRepPart.nonce) { @@ -82,49 +100,84 @@ abstract class KrbKdcRep { !rep.encKDCRepPart.flags.get(KDCOptions.RENEWABLE)) { throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } - if ((req.reqBody.from == null) || req.reqBody.from.isZero()) + + if ((req.reqBody.from == null) || req.reqBody.from.isZero()) { // verify this is allowed if ((rep.encKDCRepPart.starttime != null) && - !rep.encKDCRepPart.starttime.inClockSkew()) { + !rep.encKDCRepPart.starttime.inClockSkew()) { rep.encKDCRepPart.key.destroy(); throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); } + } - if ((req.reqBody.from != null) && !req.reqBody.from.isZero()) + if ((req.reqBody.from != null) && !req.reqBody.from.isZero()) { // verify this is allowed if ((rep.encKDCRepPart.starttime != null) && - !req.reqBody.from.equals(rep.encKDCRepPart.starttime)) { + !req.reqBody.from.equals(rep.encKDCRepPart.starttime)) { rep.encKDCRepPart.key.destroy(); throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } + } if (!req.reqBody.till.isZero() && - rep.encKDCRepPart.endtime.greaterThan(req.reqBody.till)) { + rep.encKDCRepPart.endtime.greaterThan(req.reqBody.till)) { rep.encKDCRepPart.key.destroy(); throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } - if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE)) - if (req.reqBody.rtime != null && !req.reqBody.rtime.isZero()) - // verify this is required - if ((rep.encKDCRepPart.renewTill == null) || - rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.rtime) - ) { - rep.encKDCRepPart.key.destroy(); - throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); + // RFC 6806 - Section 11 mechanism check + if (rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP) && + req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE)) { + boolean reqPaReqEncPaRep = false; + boolean repPaReqEncPaRepValid = false; + + // PA_REQ_ENC_PA_REP only required for AS requests + for (PAData pa : req.pAData) { + if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { + reqPaReqEncPaRep = true; + break; + } + } + + if (rep.encKDCRepPart.pAData != null) { + for (PAData pa : rep.encKDCRepPart.pAData) { + if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { + try { + Checksum repCksum = new Checksum( + new DerInputStream( + pa.getValue()).getDerValue()); + // The checksum is inside encKDCRepPart so we don't + // care if it's keyed or not. + repPaReqEncPaRepValid = + repCksum.verifyAnyChecksum( + req.asn1Encode(), replyKey, + KeyUsage.KU_AS_REQ); + } catch (Exception e) { + if (Krb5.DEBUG) { + e.printStackTrace(); + } + } + break; + } } + } + + if (reqPaReqEncPaRep && !repPaReqEncPaRepValid) { + throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); + } + } - if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE_OK) && - rep.encKDCRepPart.flags.get(KDCOptions.RENEWABLE)) - if (!req.reqBody.till.isZero()) - // verify this is required + if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE)) { + if (req.reqBody.rtime != null && !req.reqBody.rtime.isZero()) { + // verify this is required if ((rep.encKDCRepPart.renewTill == null) || - rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.till) - ) { + rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.rtime) + ) { rep.encKDCRepPart.key.destroy(); throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } - } - + } + } + } } diff --git a/src/share/classes/sun/security/krb5/KrbTgsRep.java b/src/share/classes/sun/security/krb5/KrbTgsRep.java index 4f5c2d6ed9048492a3a100e078f8347ddac8cd36..83f0b28c014a6087dce5687c70014e511ded1fd6 100644 --- a/src/share/classes/sun/security/krb5/KrbTgsRep.java +++ b/src/share/classes/sun/security/krb5/KrbTgsRep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -84,11 +84,22 @@ public class KrbTgsRep extends KrbKdcRep { EncTGSRepPart enc_part = new EncTGSRepPart(ref); rep.encKDCRepPart = enc_part; - check(false, req, rep); + check(false, req, rep, tgsReq.tgsReqKey); + + PrincipalName serverAlias = tgsReq.getServerAlias(); + if (serverAlias != null) { + PrincipalName repSname = enc_part.sname; + if (serverAlias.equals(repSname) || + isReferralSname(repSname)) { + serverAlias = null; + } + } this.creds = new Credentials(rep.ticket, rep.cname, + tgsReq.getClientAlias(), enc_part.sname, + serverAlias, enc_part.key, enc_part.flags, enc_part.authtime, @@ -111,4 +122,16 @@ public class KrbTgsRep extends KrbKdcRep { sun.security.krb5.internal.ccache.Credentials setCredentials() { return new sun.security.krb5.internal.ccache.Credentials(rep, secondTicket); } + + private static boolean isReferralSname(PrincipalName sname) { + if (sname != null) { + String[] snameStrings = sname.getNameStrings(); + if (snameStrings.length == 2 && + snameStrings[0].equals( + PrincipalName.TGS_DEFAULT_SRV_NAME)) { + return true; + } + } + return false; + } } diff --git a/src/share/classes/sun/security/krb5/KrbTgsReq.java b/src/share/classes/sun/security/krb5/KrbTgsReq.java index 85b7cb2e05c5703c041f417125ecfbf616b0cd35..151f68b3cd28c04626b2725a354ca004f2763c6e 100644 --- a/src/share/classes/sun/security/krb5/KrbTgsReq.java +++ b/src/share/classes/sun/security/krb5/KrbTgsReq.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -35,6 +35,7 @@ import sun.security.krb5.internal.*; import sun.security.krb5.internal.crypto.*; import java.io.IOException; import java.net.UnknownHostException; +import java.time.Instant; import java.util.Arrays; /** @@ -44,7 +45,9 @@ import java.util.Arrays; public class KrbTgsReq { private PrincipalName princName; + private PrincipalName clientAlias; private PrincipalName servName; + private PrincipalName serverAlias; private TGSReq tgsReqMessg; private KerberosTime ctime; private Ticket secondTicket = null; @@ -57,59 +60,26 @@ public class KrbTgsReq { private byte[] ibuf; // Used in CredentialsUtil - public KrbTgsReq(Credentials asCreds, - PrincipalName sname) + public KrbTgsReq(KDCOptions options, Credentials asCreds, + PrincipalName cname, PrincipalName clientAlias, + PrincipalName sname, PrincipalName serverAlias, + Ticket[] additionalTickets, PAData[] extraPAs) throws KrbException, IOException { - this(new KDCOptions(), - asCreds, - sname, - null, // KerberosTime from - null, // KerberosTime till - null, // KerberosTime rtime - null, // eTypes, // null, // int[] eTypes - null, // HostAddresses addresses - null, // AuthorizationData authorizationData - null, // Ticket[] additionalTickets - null); // EncryptionKey subSessionKey - } - - // S4U2proxy - public KrbTgsReq(Credentials asCreds, - Ticket second, - PrincipalName sname) - throws KrbException, IOException { - this(KDCOptions.with(KDCOptions.CNAME_IN_ADDL_TKT, - KDCOptions.FORWARDABLE), - asCreds, - sname, - null, - null, - null, - null, - null, - null, - new Ticket[] {second}, // the service ticket - null); - } - - // S4U2user - public KrbTgsReq(Credentials asCreds, - PrincipalName sname, - PAData extraPA) - throws KrbException, IOException { - this(KDCOptions.with(KDCOptions.FORWARDABLE), - asCreds, - asCreds.getClient(), - sname, - null, - null, - null, - null, - null, - null, - null, - null, - extraPA); // the PA-FOR-USER + this(options, + asCreds, + cname, + clientAlias, + sname, + serverAlias, + null, // KerberosTime from + null, // KerberosTime till + null, // KerberosTime rtime + null, // int[] eTypes + null, // HostAddresses addresses + null, // AuthorizationData authorizationData + additionalTickets, + null, // EncryptionKey subKey + extraPAs); } // Called by Credentials, KrbCred @@ -117,6 +87,7 @@ public class KrbTgsReq { KDCOptions options, Credentials asCreds, PrincipalName sname, + PrincipalName serverAlias, KerberosTime from, KerberosTime till, KerberosTime rtime, @@ -125,16 +96,18 @@ public class KrbTgsReq { AuthorizationData authorizationData, Ticket[] additionalTickets, EncryptionKey subKey) throws KrbException, IOException { - this(options, asCreds, asCreds.getClient(), sname, - from, till, rtime, eTypes, addresses, - authorizationData, additionalTickets, subKey, null); + this(options, asCreds, asCreds.getClient(), asCreds.getClientAlias(), + sname, serverAlias, from, till, rtime, eTypes, + addresses, authorizationData, additionalTickets, subKey, null); } private KrbTgsReq( KDCOptions options, Credentials asCreds, PrincipalName cname, + PrincipalName clientAlias, PrincipalName sname, + PrincipalName serverAlias, KerberosTime from, KerberosTime till, KerberosTime rtime, @@ -143,10 +116,12 @@ public class KrbTgsReq { AuthorizationData authorizationData, Ticket[] additionalTickets, EncryptionKey subKey, - PAData extraPA) throws KrbException, IOException { + PAData[] extraPAs) throws KrbException, IOException { princName = cname; + this.clientAlias = clientAlias; servName = sname; + this.serverAlias = serverAlias; ctime = KerberosTime.now(); // check if they are valid arguments. The optional fields @@ -216,7 +191,7 @@ public class KrbTgsReq { authorizationData, additionalTickets, subKey, - extraPA); + extraPAs); obuf = tgsReqMessg.asn1Encode(); // XXX We need to revisit this to see if can't move it @@ -282,11 +257,16 @@ public class KrbTgsReq { AuthorizationData authorizationData, Ticket[] additionalTickets, EncryptionKey subKey, - PAData extraPA) + PAData[] extraPAs) throws IOException, KrbException, UnknownHostException { KerberosTime req_till = null; if (till == null) { - req_till = new KerberosTime(0); + String d = Config.getInstance().get("libdefaults", "ticket_lifetime"); + if (d != null) { + req_till = new KerberosTime(Instant.now().plusSeconds(Config.duration(d))); + } else { + req_till = new KerberosTime(0); // Choose KDC maximum allowed + } } else { req_till = till; } @@ -340,26 +320,8 @@ public class KrbTgsReq { byte[] temp = reqBody.asn1Encode(Krb5.KRB_TGS_REQ); // if the checksum type is one of the keyed checksum types, // use session key. - Checksum cksum; - switch (Checksum.CKSUMTYPE_DEFAULT) { - case Checksum.CKSUMTYPE_RSA_MD4_DES: - case Checksum.CKSUMTYPE_DES_MAC: - case Checksum.CKSUMTYPE_DES_MAC_K: - case Checksum.CKSUMTYPE_RSA_MD4_DES_K: - case Checksum.CKSUMTYPE_RSA_MD5_DES: - case Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD: - case Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR: - case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128: - case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256: - cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp, key, + Checksum cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp, key, KeyUsage.KU_PA_TGS_REQ_CKSUM); - break; - case Checksum.CKSUMTYPE_CRC32: - case Checksum.CKSUMTYPE_RSA_MD4: - case Checksum.CKSUMTYPE_RSA_MD5: - default: - cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp); - } // Usage will be KeyUsage.KU_PA_TGS_REQ_AUTHENTICATOR @@ -375,11 +337,14 @@ public class KrbTgsReq { null).getMessage(); PAData tgsPAData = new PAData(Krb5.PA_TGS_REQ, tgs_ap_req); - return new TGSReq( - extraPA != null ? - new PAData[] {extraPA, tgsPAData } : - new PAData[] {tgsPAData}, - reqBody); + PAData[] pa; + if (extraPAs != null) { + pa = Arrays.copyOf(extraPAs, extraPAs.length + 1); + pa[extraPAs.length] = tgsPAData; + } else { + pa = new PAData[] {tgsPAData}; + } + return new TGSReq(pa, reqBody); } TGSReq getMessage() { @@ -390,6 +355,14 @@ public class KrbTgsReq { return secondTicket; } + PrincipalName getClientAlias() { + return clientAlias; + } + + PrincipalName getServerAlias() { + return serverAlias; + } + private static void debug(String message) { // System.err.println(">>> KrbTgsReq: " + message); } diff --git a/src/share/classes/sun/security/krb5/PrincipalName.java b/src/share/classes/sun/security/krb5/PrincipalName.java index 6d5ed3dde67108af35824791df65be7a0ea373df..4a16eb39c7d27480c049508fb09044a023770111 100644 --- a/src/share/classes/sun/security/krb5/PrincipalName.java +++ b/src/share/classes/sun/security/krb5/PrincipalName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -90,6 +90,11 @@ public class PrincipalName implements Cloneable { */ public static final int KRB_NT_UID = 5; + /** + * Enterprise name (alias) + */ + public static final int KRB_NT_ENTERPRISE = 10; + /** * TGS Name */ @@ -454,6 +459,7 @@ public class PrincipalName implements Cloneable { case KRB_NT_SRV_INST: case KRB_NT_SRV_XHST: case KRB_NT_UID: + case KRB_NT_ENTERPRISE: nameStrings = nameParts; nameType = type; if (realm != null) { @@ -547,7 +553,9 @@ public class PrincipalName implements Cloneable { for (int i = 0; i < nameStrings.length; i++) { if (i > 0) str.append("/"); - str.append(nameStrings[i]); + String n = nameStrings[i]; + n = n.replace("@", "\\@"); + str.append(n); } str.append("@"); str.append(nameRealm.toString()); diff --git a/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java b/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java index 14620e94483ece9940deaeaaa9ce4c58c6b8bdc4..6cfcd41d839448400348c06131b9584371367b2c 100644 --- a/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java +++ b/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, 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 @@ -33,6 +33,8 @@ package sun.security.krb5.internal; import sun.security.krb5.*; import java.io.IOException; +import java.util.LinkedList; +import java.util.List; /** * This class is a utility that contains much of the TGS-Exchange @@ -61,13 +63,11 @@ public class CredentialsUtil { if (!ccreds.isForwardable()) { throw new KrbException("S4U2self needs a FORWARDABLE ticket"); } - KrbTgsReq req = new KrbTgsReq( - ccreds, - ccreds.getClient(), - new PAData(Krb5.PA_FOR_USER, - new PAForUserEnc(client, - ccreds.getSessionKey()).asn1Encode())); - Credentials creds = req.sendAndGetCreds(); + Credentials creds = serviceCreds(KDCOptions.with(KDCOptions.FORWARDABLE), + ccreds, ccreds.getClient(), ccreds.getClient(), null, + new PAData[] {new PAData(Krb5.PA_FOR_USER, + new PAForUserEnc(client, + ccreds.getSessionKey()).asn1Encode())}); if (!creds.getClient().equals(client)) { throw new KrbException("S4U2self request not honored by KDC"); } @@ -89,11 +89,10 @@ public class CredentialsUtil { String backend, Ticket second, PrincipalName client, Credentials ccreds) throws KrbException, IOException { - KrbTgsReq req = new KrbTgsReq( - ccreds, - second, - new PrincipalName(backend)); - Credentials creds = req.sendAndGetCreds(); + Credentials creds = serviceCreds(KDCOptions.with( + KDCOptions.CNAME_IN_ADDL_TKT, KDCOptions.FORWARDABLE), + ccreds, ccreds.getClient(), new PrincipalName(backend), + new Ticket[] {second}, null); if (!creds.getClient().equals(client)) { throw new KrbException("S4U2proxy request not honored by KDC"); } @@ -114,53 +113,9 @@ public class CredentialsUtil { public static Credentials acquireServiceCreds( String service, Credentials ccreds) throws KrbException, IOException { - PrincipalName sname = new PrincipalName(service); - String serviceRealm = sname.getRealmString(); - String localRealm = ccreds.getClient().getRealmString(); - - if (localRealm.equals(serviceRealm)) { - if (DEBUG) { - System.out.println( - ">>> Credentials acquireServiceCreds: same realm"); - } - return serviceCreds(sname, ccreds); - } - Credentials theCreds = null; - - boolean[] okAsDelegate = new boolean[1]; - Credentials theTgt = getTGTforRealm(localRealm, serviceRealm, - ccreds, okAsDelegate); - if (theTgt != null) { - if (DEBUG) { - System.out.println(">>> Credentials acquireServiceCreds: " - + "got right tgt"); - System.out.println(">>> Credentials acquireServiceCreds: " - + "obtaining service creds for " + sname); - } - - try { - theCreds = serviceCreds(sname, theTgt); - } catch (Exception exc) { - if (DEBUG) { - System.out.println(exc); - } - theCreds = null; - } - } - - if (theCreds != null) { - if (DEBUG) { - System.out.println(">>> Credentials acquireServiceCreds: " - + "returning creds:"); - Credentials.printDebug(theCreds); - } - if (!okAsDelegate[0]) { - theCreds.resetDelegate(); - } - return theCreds; - } - throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED, - "No service creds"); + PrincipalName sname = new PrincipalName(service, + PrincipalName.KRB_NT_SRV_HST); + return serviceCreds(sname, ccreds); } /** @@ -305,6 +260,153 @@ public class CredentialsUtil { private static Credentials serviceCreds( PrincipalName service, Credentials ccreds) throws KrbException, IOException { - return new KrbTgsReq(ccreds, service).sendAndGetCreds(); + return serviceCreds(new KDCOptions(), ccreds, + ccreds.getClient(), service, null, null); + } + + /* + * Obtains credentials for a service (TGS). + * Cross-realm referrals are handled if enabled. A fallback scheme + * without cross-realm referrals supports is used in case of server + * error to maintain backward compatibility. + */ + private static Credentials serviceCreds( + KDCOptions options, Credentials asCreds, + PrincipalName cname, PrincipalName sname, + Ticket[] additionalTickets, PAData[] extraPAs) + throws KrbException, IOException { + if (!Config.DISABLE_REFERRALS) { + try { + return serviceCredsReferrals(options, asCreds, + cname, sname, additionalTickets, extraPAs); + } catch (KrbException e) { + // Server may raise an error if CANONICALIZE is true. + // Try CANONICALIZE false. + } + } + return serviceCredsSingle(options, asCreds, cname, + asCreds.getClientAlias(), sname, sname, additionalTickets, + extraPAs); + } + + /* + * Obtains credentials for a service (TGS). + * May handle and follow cross-realm referrals as defined by RFC 6806. + */ + private static Credentials serviceCredsReferrals( + KDCOptions options, Credentials asCreds, + PrincipalName cname, PrincipalName sname, + Ticket[] additionalTickets, PAData[] extraPAs) + throws KrbException, IOException { + options = new KDCOptions(options.toBooleanArray()); + options.set(KDCOptions.CANONICALIZE, true); + PrincipalName cSname = sname; + PrincipalName refSname = sname; // May change with referrals + Credentials creds = null; + boolean isReferral = false; + List referrals = new LinkedList<>(); + PrincipalName clientAlias = asCreds.getClientAlias(); + while (referrals.size() <= Config.MAX_REFERRALS) { + ReferralsCache.ReferralCacheEntry ref = + ReferralsCache.get(cname, sname, refSname.getRealmString()); + String toRealm = null; + if (ref == null) { + creds = serviceCredsSingle(options, asCreds, cname, + clientAlias, refSname, cSname, additionalTickets, + extraPAs); + PrincipalName server = creds.getServer(); + if (!refSname.equals(server)) { + String[] serverNameStrings = server.getNameStrings(); + if (serverNameStrings.length == 2 && + serverNameStrings[0].equals( + PrincipalName.TGS_DEFAULT_SRV_NAME) && + !refSname.getRealmAsString().equals(serverNameStrings[1])) { + // Server Name (sname) has the following format: + // krbtgt/TO-REALM.COM@FROM-REALM.COM + ReferralsCache.put(cname, sname, server.getRealmString(), + serverNameStrings[1], creds); + toRealm = serverNameStrings[1]; + isReferral = true; + asCreds = creds; + } + } + } else { + toRealm = ref.getToRealm(); + asCreds = ref.getCreds(); + isReferral = true; + } + if (isReferral) { + if (referrals.contains(toRealm)) { + // Referrals loop detected + return null; + } + refSname = new PrincipalName(refSname.getNameString(), + refSname.getNameType(), toRealm); + referrals.add(toRealm); + isReferral = false; + continue; + } + break; + } + return creds; + } + + /* + * Obtains credentials for a service (TGS). + * If the service realm is different than the one in the TGT, a new TGT for + * the service realm is obtained first (see getTGTforRealm call). This is + * not expected when following cross-realm referrals because the referral + * TGT realm matches the service realm. + */ + private static Credentials serviceCredsSingle( + KDCOptions options, Credentials asCreds, + PrincipalName cname, PrincipalName clientAlias, + PrincipalName refSname, PrincipalName sname, + Ticket[] additionalTickets, PAData[] extraPAs) + throws KrbException, IOException { + Credentials theCreds = null; + boolean[] okAsDelegate = new boolean[]{true}; + String[] serverAsCredsNames = asCreds.getServer().getNameStrings(); + String tgtRealm = serverAsCredsNames[1]; + String serviceRealm = refSname.getRealmString(); + if (!serviceRealm.equals(tgtRealm)) { + // This is a cross-realm service request + if (DEBUG) { + System.out.println(">>> serviceCredsSingle:" + + " cross-realm authentication"); + System.out.println(">>> serviceCredsSingle:" + + " obtaining credentials from " + tgtRealm + + " to " + serviceRealm); + } + Credentials newTgt = getTGTforRealm(tgtRealm, serviceRealm, + asCreds, okAsDelegate); + if (newTgt == null) { + throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED, + "No service creds"); + } + if (DEBUG) { + System.out.println(">>> Cross-realm TGT Credentials" + + " serviceCredsSingle: "); + Credentials.printDebug(newTgt); + } + asCreds = newTgt; + cname = asCreds.getClient(); + } else if (DEBUG) { + System.out.println(">>> Credentials serviceCredsSingle:" + + " same realm"); + } + KrbTgsReq req = new KrbTgsReq(options, asCreds, cname, clientAlias, + refSname, sname, additionalTickets, extraPAs); + theCreds = req.sendAndGetCreds(); + if (theCreds != null) { + if (DEBUG) { + System.out.println(">>> TGS credentials serviceCredsSingle:"); + Credentials.printDebug(theCreds); + } + if (!okAsDelegate[0]) { + theCreds.resetDelegate(); + } + } + return theCreds; } } diff --git a/src/share/classes/sun/security/krb5/internal/EncASRepPart.java b/src/share/classes/sun/security/krb5/internal/EncASRepPart.java index 7e5d037de5d56a17cc571f2c11a917fb347c75c1..ff9382e83f44fb48dc234eb5935c2c946d178b70 100644 --- a/src/share/classes/sun/security/krb5/internal/EncASRepPart.java +++ b/src/share/classes/sun/security/krb5/internal/EncASRepPart.java @@ -47,7 +47,8 @@ public class EncASRepPart extends EncKDCRepPart { KerberosTime new_endtime, KerberosTime new_renewTill, PrincipalName new_sname, - HostAddresses new_caddr) { + HostAddresses new_caddr, + PAData[] new_pAData) { super( new_key, new_lastReq, @@ -60,6 +61,7 @@ public class EncASRepPart extends EncKDCRepPart { new_renewTill, new_sname, new_caddr, + new_pAData, Krb5.KRB_ENC_AS_REP_PART ); //may need to use Krb5.KRB_ENC_TGS_REP_PART to mimic diff --git a/src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java b/src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java index 2dd4c841ccc7c72cbb5e4b776a2b62d0cc12aca3..5c603649633e891495176b696ff2dbe7b12af33d 100644 --- a/src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java +++ b/src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java @@ -31,7 +31,6 @@ package sun.security.krb5.internal; import sun.security.krb5.*; -import sun.security.krb5.EncryptionKey; import sun.security.util.*; import java.util.Vector; import java.io.IOException; @@ -41,19 +40,20 @@ import java.math.BigInteger; * Implements the ASN.1 EncKDCRepPart type. * *

    - * EncKDCRepPart ::= SEQUENCE { - * key [0] EncryptionKey, - * last-req [1] LastReq, - * nonce [2] UInt32, - * key-expiration [3] KerberosTime OPTIONAL, - * flags [4] TicketFlags, - * authtime [5] KerberosTime, - * starttime [6] KerberosTime OPTIONAL, - * endtime [7] KerberosTime, - * renew-till [8] KerberosTime OPTIONAL, - * srealm [9] Realm, - * sname [10] PrincipalName, - * caddr [11] HostAddresses OPTIONAL + * EncKDCRepPart ::= SEQUENCE { + * key [0] EncryptionKey, + * last-req [1] LastReq, + * nonce [2] UInt32, + * key-expiration [3] KerberosTime OPTIONAL, + * flags [4] TicketFlags, + * authtime [5] KerberosTime, + * starttime [6] KerberosTime OPTIONAL, + * endtime [7] KerberosTime, + * renew-till [8] KerberosTime OPTIONAL, + * srealm [9] Realm, + * sname [10] PrincipalName, + * caddr [11] HostAddresses OPTIONAL, + * encrypted-pa-data [12] SEQUENCE OF PA-DATA OPTIONAL * } * * @@ -76,6 +76,7 @@ public class EncKDCRepPart { public KerberosTime renewTill; //optional public PrincipalName sname; public HostAddresses caddr; //optional + public PAData[] pAData; //optional public int msgType; //not included in sequence public EncKDCRepPart( @@ -90,6 +91,7 @@ public class EncKDCRepPart { KerberosTime new_renewTill, PrincipalName new_sname, HostAddresses new_caddr, + PAData[] new_pAData, int new_msgType) { key = new_key; lastReq = new_lastReq; @@ -102,6 +104,7 @@ public class EncKDCRepPart { renewTill = new_renewTill; sname = new_sname; caddr = new_caddr; + pAData = new_pAData; msgType = new_msgType; } @@ -160,6 +163,9 @@ public class EncKDCRepPart { if (der.getData().available() > 0) { caddr = HostAddresses.parse(der.getData(), (byte) 0x0B, true); } + if (der.getData().available() > 0) { + pAData = PAData.parseSequence(der.getData(), (byte) 0x0C, true); + } // We observe extra data from MSAD /*if (der.getData().available() > 0) { throw new Asn1Exception(Krb5.ASN1_BAD_ID); @@ -175,47 +181,58 @@ public class EncKDCRepPart { */ public byte[] asn1Encode(int rep_type) throws Asn1Exception, IOException { + DerOutputStream bytes; DerOutputStream temp = new DerOutputStream(); - DerOutputStream bytes = new DerOutputStream(); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + DerOutputStream out = new DerOutputStream(); + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x00), key.asn1Encode()); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x01), lastReq.asn1Encode()); temp.putInteger(BigInteger.valueOf(nonce)); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x02), temp); if (keyExpiration != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x03), keyExpiration.asn1Encode()); } - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x04), flags.asn1Encode()); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x05), authtime.asn1Encode()); if (starttime != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x06), starttime.asn1Encode()); } - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x07), endtime.asn1Encode()); if (renewTill != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x08), renewTill.asn1Encode()); } - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x09), sname.getRealm().asn1Encode()); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x0A), sname.asn1Encode()); if (caddr != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x0B), caddr.asn1Encode()); } + if (pAData != null && pAData.length > 0) { + temp = new DerOutputStream(); + for (int i = 0; i < pAData.length; i++) { + temp.write(pAData[i].asn1Encode()); + } + bytes = new DerOutputStream(); + bytes.write(DerValue.tag_SequenceOf, temp); + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, + true, (byte) 0x0C), bytes); + } //should use the rep_type to build the encoding //but other implementations do not; it is ignored and //the cached msgType is used instead temp = new DerOutputStream(); - temp.write(DerValue.tag_Sequence, bytes); + temp.write(DerValue.tag_Sequence, out); bytes = new DerOutputStream(); bytes.write(DerValue.createTag(DerValue.TAG_APPLICATION, true, (byte) msgType), temp); diff --git a/src/share/classes/sun/security/krb5/internal/EncTGSRepPart.java b/src/share/classes/sun/security/krb5/internal/EncTGSRepPart.java index cdca881ebe44e3972bff5b78f8253f86b4b42546..b1f192e72e4d8f0c09f86eddbd1e6c59ca61e92c 100644 --- a/src/share/classes/sun/security/krb5/internal/EncTGSRepPart.java +++ b/src/share/classes/sun/security/krb5/internal/EncTGSRepPart.java @@ -46,7 +46,8 @@ public class EncTGSRepPart extends EncKDCRepPart { KerberosTime new_endtime, KerberosTime new_renewTill, PrincipalName new_sname, - HostAddresses new_caddr) { + HostAddresses new_caddr, + PAData[] new_pAData) { super( new_key, new_lastReq, @@ -59,6 +60,7 @@ public class EncTGSRepPart extends EncKDCRepPart { new_renewTill, new_sname, new_caddr, + new_pAData, Krb5.KRB_ENC_TGS_REP_PART); } diff --git a/src/share/classes/sun/security/krb5/internal/HostAddress.java b/src/share/classes/sun/security/krb5/internal/HostAddress.java index f3d1d87467c5463507311b39e7572ed2f4f07b2e..77e00a0d61dc7d4e9e0ea55df74173787887208a 100644 --- a/src/share/classes/sun/security/krb5/internal/HostAddress.java +++ b/src/share/classes/sun/security/krb5/internal/HostAddress.java @@ -39,6 +39,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.UnknownHostException; import java.io.IOException; +import java.util.Arrays; /** * Implements the ASN.1 HostAddress type. @@ -295,4 +296,11 @@ public class HostAddress implements Cloneable { } } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(Arrays.toString(address)); + sb.append('(').append(addrType).append(')'); + return sb.toString(); + } } diff --git a/src/share/classes/sun/security/krb5/internal/HostAddresses.java b/src/share/classes/sun/security/krb5/internal/HostAddresses.java index 8dc9a2853e16229f445823c81503b1e15e307750..38bb6a348bccf958061f40aa0ad7dedfb22a994d 100644 --- a/src/share/classes/sun/security/krb5/internal/HostAddresses.java +++ b/src/share/classes/sun/security/krb5/internal/HostAddresses.java @@ -31,16 +31,14 @@ package sun.security.krb5.internal; +import sun.security.krb5.Config; import sun.security.krb5.PrincipalName; import sun.security.krb5.KrbException; import sun.security.krb5.Asn1Exception; import sun.security.util.*; -import java.util.Vector; -import java.util.ArrayList; -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.UnknownHostException; + +import java.net.*; +import java.util.*; import java.io.IOException; import sun.security.krb5.internal.ccache.CCacheOutputStream; @@ -250,6 +248,10 @@ public class HostAddresses implements Cloneable { */ public void writeAddrs(CCacheOutputStream cos) throws IOException { + if (addresses == null || addresses.length == 0) { + cos.write32(0); + return; + } cos.write32(addresses.length); for (int i = 0; i < addresses.length; i++) { cos.write16(addresses[i].addrType); @@ -289,34 +291,35 @@ public class HostAddresses implements Cloneable { */ public static HostAddresses getLocalAddresses() throws IOException { - String hostname = null; - InetAddress[] inetAddresses = null; + Set all = new LinkedHashSet<>(); try { - InetAddress localHost = InetAddress.getLocalHost(); - hostname = localHost.getHostName(); - inetAddresses = InetAddress.getAllByName(hostname); - HostAddress[] hAddresses = new HostAddress[inetAddresses.length]; - for (int i = 0; i < inetAddresses.length; i++) - { - hAddresses[i] = new HostAddress(inetAddresses[i]); - } if (DEBUG) { - System.out.println(">>> KrbKdcReq local addresses for " - + hostname + " are: "); - - for (int i = 0; i < inetAddresses.length; i++) { - System.out.println("\n\t" + inetAddresses[i]); - if (inetAddresses[i] instanceof Inet4Address) - System.out.println("IPv4 address"); - if (inetAddresses[i] instanceof Inet6Address) - System.out.println("IPv6 address"); + System.out.println(">>> KrbKdcReq local addresses are:"); + } + String extra = Config.getInstance().getAll( + "libdefaults", "extra_addresses"); + if (extra != null) { + for (String s: extra.split("\\s+")) { + all.add(InetAddress.getByName(s)); + if (DEBUG) { + System.out.println(" extra_addresses: " + + InetAddress.getByName(s)); + } } } - return (new HostAddresses(hAddresses)); + for (NetworkInterface ni: + Collections.list(NetworkInterface.getNetworkInterfaces())) { + if (DEBUG) { + System.out.println(" NetworkInterface " + ni + ":"); + System.out.println(" " + + Collections.list(ni.getInetAddresses())); + } + all.addAll(Collections.list(ni.getInetAddresses())); + } + return new HostAddresses(all.toArray(new InetAddress[all.size()])); } catch (Exception exc) { throw new IOException(exc.toString()); } - } /** @@ -335,4 +338,9 @@ public class HostAddresses implements Cloneable { for (int i = 0; i < inetAddresses.length; i++) addresses[i] = new HostAddress(inetAddresses[i]); } + + @Override + public String toString() { + return Arrays.toString(addresses); + } } diff --git a/src/share/classes/sun/security/krb5/internal/KDCOptions.java b/src/share/classes/sun/security/krb5/internal/KDCOptions.java index a3d93021710d75df29a9f6b10d922b008b6dec6b..eb1b6f596c9502dd24943acba2e1a8c974cd4220 100644 --- a/src/share/classes/sun/security/krb5/internal/KDCOptions.java +++ b/src/share/classes/sun/security/krb5/internal/KDCOptions.java @@ -140,6 +140,7 @@ public class KDCOptions extends KerberosFlags { public static final int UNUSED10 = 10; public static final int UNUSED11 = 11; public static final int CNAME_IN_ADDL_TKT = 14; + public static final int CANONICALIZE = 15; public static final int RENEWABLE_OK = 27; public static final int ENC_TKT_IN_SKEY = 28; public static final int RENEW = 30; @@ -160,7 +161,8 @@ public class KDCOptions extends KerberosFlags { "UNUSED11", //11; null,null, "CNAME_IN_ADDL_TKT",//14; - null,null,null,null,null,null,null,null,null,null,null,null, + "CANONICALIZE", //15; + null,null,null,null,null,null,null,null,null,null,null, "RENEWABLE_OK", //27; "ENC_TKT_IN_SKEY", //28; null, diff --git a/src/share/classes/sun/security/krb5/internal/KDCReq.java b/src/share/classes/sun/security/krb5/internal/KDCReq.java index 16591e80404f263fa7850699d55a1f48779187c5..12d410745d5ee1c5a0475a9cb1e5ec6c0b7b0fee 100644 --- a/src/share/classes/sun/security/krb5/internal/KDCReq.java +++ b/src/share/classes/sun/security/krb5/internal/KDCReq.java @@ -59,9 +59,9 @@ import java.math.BigInteger; public class KDCReq { public KDCReqBody reqBody; + public PAData[] pAData = null; //optional private int pvno; private int msgType; - private PAData[] pAData = null; //optional public KDCReq(PAData[] new_pAData, KDCReqBody new_reqBody, int req_type) throws IOException { @@ -144,23 +144,7 @@ public class KDCReq { } else { throw new Asn1Exception(Krb5.ASN1_BAD_ID); } - if ((der.getData().peekByte() & 0x1F) == 0x03) { - subDer = der.getData().getDerValue(); - DerValue subsubDer = subDer.getData().getDerValue(); - if (subsubDer.getTag() != DerValue.tag_SequenceOf) { - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - Vector v = new Vector<>(); - while (subsubDer.getData().available() > 0) { - v.addElement(new PAData(subsubDer.getData().getDerValue())); - } - if (v.size() > 0) { - pAData = new PAData[v.size()]; - v.copyInto(pAData); - } - } else { - pAData = null; - } + pAData = PAData.parseSequence(der.getData(), (byte) 0x03, true); subDer = der.getData().getDerValue(); if ((subDer.getTag() & 0x01F) == 0x04) { DerValue subsubDer = subDer.getData().getDerValue(); diff --git a/src/share/classes/sun/security/krb5/internal/KRBError.java b/src/share/classes/sun/security/krb5/internal/KRBError.java index 6569cbc4fb5f8ac402fe9ab44569d5a988106e85..5b51706d3275bd0cb3cf3d0536d1ba30e34690ec 100644 --- a/src/share/classes/sun/security/krb5/internal/KRBError.java +++ b/src/share/classes/sun/security/krb5/internal/KRBError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -90,6 +90,7 @@ public class KRBError implements java.io.Serializable { private KerberosTime sTime; private Integer suSec; private int errorCode; + private Realm crealm; //optional private PrincipalName cname; //optional private PrincipalName sname; private String eText; //optional @@ -138,6 +139,7 @@ public class KRBError implements java.io.Serializable { sTime = new_sTime; suSec = new_suSec; errorCode = new_errorCode; + crealm = new_cname != null ? new_cname.getRealm() : null; cname = new_cname; sname = new_sname; eText = new_eText; @@ -166,6 +168,7 @@ public class KRBError implements java.io.Serializable { sTime = new_sTime; suSec = new_suSec; errorCode = new_errorCode; + crealm = new_cname != null ? new_cname.getRealm() : null; cname = new_cname; sname = new_sname; eText = new_eText; @@ -262,6 +265,10 @@ public class KRBError implements java.io.Serializable { pa = paList.toArray(new PAData[paList.size()]); } + public final Realm getClientRealm() { + return crealm; + } + public final KerberosTime getServerTime() { return sTime; } @@ -349,7 +356,7 @@ public class KRBError implements java.io.Serializable { errorCode = subDer.getData().getBigInteger().intValue(); } else throw new Asn1Exception(Krb5.ASN1_BAD_ID); - Realm crealm = Realm.parse(der.getData(), (byte)0x07, true); + crealm = Realm.parse(der.getData(), (byte)0x07, true); cname = PrincipalName.parse(der.getData(), (byte)0x08, true, crealm); Realm realm = Realm.parse(der.getData(), (byte)0x09, false); sname = PrincipalName.parse(der.getData(), (byte)0x0A, false, realm); @@ -393,6 +400,9 @@ public class KRBError implements java.io.Serializable { System.out.println("\t suSec is " + suSec); System.out.println("\t error code is " + errorCode); System.out.println("\t error Message is " + Krb5.getErrorMessage(errorCode)); + if (crealm != null) { + System.out.println("\t crealm is " + crealm.toString()); + } if (cname != null) { System.out.println("\t cname is " + cname.toString()); } @@ -442,8 +452,10 @@ public class KRBError implements java.io.Serializable { temp.putInteger(BigInteger.valueOf(errorCode)); bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x06), temp); + if (crealm != null) { + bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x07), crealm.asn1Encode()); + } if (cname != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x07), cname.getRealm().asn1Encode()); bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x08), cname.asn1Encode()); } @@ -488,6 +500,7 @@ public class KRBError implements java.io.Serializable { isEqual(sTime, other.sTime) && isEqual(suSec, other.suSec) && errorCode == other.errorCode && + isEqual(crealm, other.crealm) && isEqual(cname, other.cname) && isEqual(sname, other.sname) && isEqual(eText, other.eText) && @@ -508,6 +521,7 @@ public class KRBError implements java.io.Serializable { if (sTime != null) result = 37 * result + sTime.hashCode(); if (suSec != null) result = 37 * result + suSec.hashCode(); result = 37 * result + errorCode; + if (crealm != null) result = 37 * result + crealm.hashCode(); if (cname != null) result = 37 * result + cname.hashCode(); if (sname != null) result = 37 * result + sname.hashCode(); if (eText != null) result = 37 * result + eText.hashCode(); diff --git a/src/share/classes/sun/security/krb5/internal/KerberosTime.java b/src/share/classes/sun/security/krb5/internal/KerberosTime.java index 3beaac873ced90df80925fa6dc7128f3e6e0dbbe..64225c8eede8e0064b417f88f1e51c35238d6f1a 100644 --- a/src/share/classes/sun/security/krb5/internal/KerberosTime.java +++ b/src/share/classes/sun/security/krb5/internal/KerberosTime.java @@ -38,6 +38,7 @@ import sun.security.util.DerOutputStream; import sun.security.util.DerValue; import java.io.IOException; +import java.time.Instant; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; @@ -128,6 +129,14 @@ public class KerberosTime { this(time.getTime(), 0); } + /** + * Creates a KerberosTime object from an Instant object + */ + public KerberosTime(Instant instant) { + this(instant.getEpochSecond()*1000 + instant.getNano()/1000000L, + instant.getNano()/1000%1000); + } + /** * Creates a KerberosTime object for now. It uses System.nanoTime() * to get a more precise time than "new Date()". diff --git a/src/share/classes/sun/security/krb5/internal/Krb5.java b/src/share/classes/sun/security/krb5/internal/Krb5.java index 2be21dc78a8e609799cb4590a5b8b18ed9e35584..a2e7e3b86991325b36464e6aba937f86467dc819 100644 --- a/src/share/classes/sun/security/krb5/internal/Krb5.java +++ b/src/share/classes/sun/security/krb5/internal/Krb5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -70,6 +70,7 @@ public class Krb5 { public static final int TKT_OPTS_PRE_AUTHENT = 10; public static final int TKT_OPTS_HW_AUTHENT = 11; public static final int TKT_OPTS_DELEGATE = 13; + public static final int TKT_OPTS_ENC_PA_REP = 15; public static final int TKT_OPTS_MAX = 31; // KDC Options @@ -163,6 +164,9 @@ public class Krb5 { // S4U2user info public static final int PA_FOR_USER = 129; + // FAST (RFC 6806) + public static final int PA_REQ_ENC_PA_REP = 149; + //-------------------------------+------------- //authorization data type |ad-type value //-------------------------------+------------- @@ -265,6 +269,7 @@ public class Krb5 { public static final int KRB_ERR_RESPONSE_TOO_BIG = 52; //Response too big for UDP, retry with TCP public static final int KRB_ERR_GENERIC = 60; //Generic error (description in e-text) public static final int KRB_ERR_FIELD_TOOLONG = 61; //Field is too long for this implementation + public static final int KRB_ERR_WRONG_REALM = 68; //Wrong realm public static final int KRB_CRYPTO_NOT_SUPPORT = 100; //Client does not support this crypto type public static final int KRB_AP_ERR_NOREALM = 62; public static final int KRB_AP_ERR_GEN_CRED = 63; diff --git a/src/share/classes/sun/security/krb5/internal/NetClient.java b/src/share/classes/sun/security/krb5/internal/NetClient.java index 62243560ca19e119161fab40283274941725d620..ab4fe40c3f18f30091f9ea8d8ebb7ca827ce8cc3 100644 --- a/src/share/classes/sun/security/krb5/internal/NetClient.java +++ b/src/share/classes/sun/security/krb5/internal/NetClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -103,7 +103,7 @@ class TCPClient extends NetClient { } try { - return IOUtils.readFully(in, len, true); + return IOUtils.readExactlyNBytes(in, len); } catch (IOException ioe) { if (Krb5.DEBUG) { System.out.println( diff --git a/src/share/classes/sun/security/krb5/internal/PAData.java b/src/share/classes/sun/security/krb5/internal/PAData.java index f3fdb0b94578639b5c1aafdf019cdcc2e1920d45..fd1429a4c35578f542320df783b5d765be96d5c5 100644 --- a/src/share/classes/sun/security/krb5/internal/PAData.java +++ b/src/share/classes/sun/security/krb5/internal/PAData.java @@ -1,4 +1,6 @@ /* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -30,10 +32,12 @@ package sun.security.krb5.internal; -import sun.security.krb5.KrbException; +import sun.security.krb5.internal.crypto.EType; import sun.security.util.*; import sun.security.krb5.Asn1Exception; import java.io.IOException; +import java.util.Vector; + import sun.security.krb5.internal.util.KerberosString; /** @@ -138,6 +142,41 @@ public class PAData { return ((pADataValue == null) ? null : pADataValue.clone()); } + /** + * Parse (unmarshal) a PAData from a DER input stream. This form + * parsing might be used when expanding a value which is part of + * a constructed sequence and uses explicitly tagged type. + * + * @exception Asn1Exception if an Asn1Exception occurs. + * @param data the Der input stream value, which contains one or more + * marshaled values. + * @param explicitTag tag number. + * @param optional indicates if this data field is optional. + * @return an array of PAData. + */ + public static PAData[] parseSequence(DerInputStream data, + byte explicitTag, boolean optional) + throws Asn1Exception, IOException { + if ((optional) && + (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) + return null; + DerValue subDer = data.getDerValue(); + DerValue subsubDer = subDer.getData().getDerValue(); + if (subsubDer.getTag() != DerValue.tag_SequenceOf) { + throw new Asn1Exception(Krb5.ASN1_BAD_ID); + } + Vector v = new Vector<>(); + while (subsubDer.getData().available() > 0) { + v.addElement(new PAData(subsubDer.getData().getDerValue())); + } + if (v.size() > 0) { + PAData[] pas = new PAData[v.size()]; + v.copyInto(pas); + return pas; + } + return null; + } + /** * Gets the preferred etype from the PAData array. * 1. ETYPE-INFO2-ENTRY with unknown s2kparams ignored @@ -169,8 +208,8 @@ public class PAData { while (d2.data.available() > 0) { DerValue value = d2.data.getDerValue(); ETypeInfo2 tmp = new ETypeInfo2(value); - if (tmp.getParams() == null) { - // we don't support non-null s2kparams + if (EType.isNewer(tmp.getEType()) || tmp.getParams() == null) { + // we don't support non-null s2kparams for old etypes return tmp.getEType(); } } @@ -236,8 +275,9 @@ public class PAData { while (d2.data.available() > 0) { DerValue value = d2.data.getDerValue(); ETypeInfo2 tmp = new ETypeInfo2(value); - if (tmp.getParams() == null && tmp.getEType() == eType) { - // we don't support non-null s2kparams + if (tmp.getEType() == eType && + (EType.isNewer(eType) || tmp.getParams() == null)) { + // we don't support non-null s2kparams for old etypes return new SaltAndParams(tmp.getSalt(), tmp.getParams()); } } diff --git a/src/share/classes/sun/security/krb5/internal/PAForUserEnc.java b/src/share/classes/sun/security/krb5/internal/PAForUserEnc.java index 42c9caaedbb72a69051847a8a7134a6aa3d30b31..a1952ffee5e6fdea54b231e93f1d83f56a287b89 100644 --- a/src/share/classes/sun/security/krb5/internal/PAForUserEnc.java +++ b/src/share/classes/sun/security/krb5/internal/PAForUserEnc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, 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 @@ -133,6 +133,7 @@ public class PAForUserEnc { bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), name.getRealm().asn1Encode()); try { + // MS-SFU 2.2.1: use hmac-md5 checksum regardless of key type Checksum cks = new Checksum( Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR, getS4UByteArray(), diff --git a/src/share/classes/sun/security/krb5/internal/ReferralsCache.java b/src/share/classes/sun/security/krb5/internal/ReferralsCache.java new file mode 100644 index 0000000000000000000000000000000000000000..970d432aba1e52a39548d3fb66162b34e6810fdc --- /dev/null +++ b/src/share/classes/sun/security/krb5/internal/ReferralsCache.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.security.krb5.internal; + +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import sun.security.krb5.Credentials; +import sun.security.krb5.PrincipalName; + +/* + * ReferralsCache class implements a cache scheme for referral TGTs as + * described in RFC 6806 - 10. Caching Information. The goal is to optimize + * resources (such as network traffic) when a client requests credentials for a + * service principal to a given KDC. If a referral TGT was previously received, + * cached information is used instead of issuing a new query. Once a referral + * TGT expires, the corresponding referral entry in the cache is removed. + */ +final class ReferralsCache { + + private static Map> + referralsMap = new HashMap<>(); + + static private final class ReferralCacheKey { + private PrincipalName cname; + private PrincipalName sname; + ReferralCacheKey (PrincipalName cname, PrincipalName sname) { + this.cname = cname; + this.sname = sname; + } + public boolean equals(Object other) { + if (!(other instanceof ReferralCacheKey)) + return false; + ReferralCacheKey that = (ReferralCacheKey)other; + return cname.equals(that.cname) && + sname.equals(that.sname); + } + public int hashCode() { + return cname.hashCode() + sname.hashCode(); + } + } + + static final class ReferralCacheEntry { + private final Credentials creds; + private final String toRealm; + ReferralCacheEntry(Credentials creds, String toRealm) { + this.creds = creds; + this.toRealm = toRealm; + } + Credentials getCreds() { + return creds; + } + String getToRealm() { + return toRealm; + } + } + + /* + * Add a new referral entry to the cache, including: client principal, + * service principal, source KDC realm, destination KDC realm and + * referral TGT. + * + * If a loop is generated when adding the new referral, the first hop is + * automatically removed. For example, let's assume that adding a + * REALM-3.COM -> REALM-1.COM referral generates the following loop: + * REALM-1.COM -> REALM-2.COM -> REALM-3.COM -> REALM-1.COM. Then, + * REALM-1.COM -> REALM-2.COM referral entry is removed from the cache. + */ + static synchronized void put(PrincipalName cname, PrincipalName service, + String fromRealm, String toRealm, Credentials creds) { + ReferralCacheKey k = new ReferralCacheKey(cname, service); + pruneExpired(k); + if (creds.getEndTime().before(new Date())) { + return; + } + Map entries = referralsMap.get(k); + if (entries == null) { + entries = new HashMap(); + referralsMap.put(k, entries); + } + entries.remove(fromRealm); + ReferralCacheEntry newEntry = new ReferralCacheEntry(creds, toRealm); + entries.put(fromRealm, newEntry); + + // Remove loops within the cache + ReferralCacheEntry current = newEntry; + List seen = new LinkedList<>(); + while (current != null) { + if (seen.contains(current)) { + // Loop found. Remove the first referral to cut the loop. + entries.remove(newEntry.getToRealm()); + break; + } + seen.add(current); + current = entries.get(current.getToRealm()); + } + } + + /* + * Obtain a referral entry from the cache given a client principal, + * service principal and a source KDC realm. + */ + static synchronized ReferralCacheEntry get(PrincipalName cname, + PrincipalName service, String fromRealm) { + ReferralCacheKey k = new ReferralCacheKey(cname, service); + pruneExpired(k); + Map entries = referralsMap.get(k); + if (entries != null) { + ReferralCacheEntry toRef = entries.get(fromRealm); + if (toRef != null) { + return toRef; + } + } + return null; + } + + /* + * Remove referral entries from the cache when referral TGTs expire. + */ + private static void pruneExpired(ReferralCacheKey k) { + Date now = new Date(); + Map entries = referralsMap.get(k); + if (entries != null) { + for (Entry mapEntry : + entries.entrySet()) { + if (mapEntry.getValue().getCreds().getEndTime().before(now)) { + entries.remove(mapEntry.getKey()); + } + } + } + } +} diff --git a/src/share/classes/sun/security/krb5/internal/TicketFlags.java b/src/share/classes/sun/security/krb5/internal/TicketFlags.java index 1f77e0f070ee7d25e3c7c60e556fd91e18b5ae75..1b3a18215f4e33db2971b966fe22e8344e77c49d 100644 --- a/src/share/classes/sun/security/krb5/internal/TicketFlags.java +++ b/src/share/classes/sun/security/krb5/internal/TicketFlags.java @@ -51,7 +51,8 @@ import java.io.IOException; * renewable(8), * initial(9), * pre-authent(10), - * hw-authent(11) + * hw-authent(11), + * enc-pa-rep(15) * } */ public class TicketFlags extends KerberosFlags { @@ -178,6 +179,9 @@ public class TicketFlags extends KerberosFlags { case 11: sb.append("HW-AUTHENT;"); break; + case 15: + sb.append("ENC-PA-REP;"); + break; } } } diff --git a/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java b/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java index c7d9d2adef9cd0430dc5fc7351068004612124b0..a73af4614fc81080cb458d7e71e5fe84cfa77bda 100644 --- a/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java +++ b/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java @@ -128,7 +128,7 @@ public class CCacheInputStream extends KrbDataInputStream implements FileCCacheC length--; for (int i = 0; i <= length; i++) { namelength = readLength4(); - byte[] bytes = IOUtils.readFully(this, namelength, true); + byte[] bytes = IOUtils.readExactlyNBytes(this, namelength); result.add(new String(bytes)); } if (result.isEmpty()) { @@ -186,7 +186,7 @@ public class CCacheInputStream extends KrbDataInputStream implements FileCCacheC if (version == KRB5_FCC_FVNO_3) read(2); /* keytype recorded twice in fvno 3 */ keyLen = readLength4(); - byte[] bytes = IOUtils.readFully(this, keyLen, true); + byte[] bytes = IOUtils.readExactlyNBytes(this, keyLen); return new EncryptionKey(bytes, keyType, new Integer(version)); } @@ -239,7 +239,7 @@ public class CCacheInputStream extends KrbDataInputStream implements FileCCacheC for (int i = 0; i < num; i++) { adtype = read(2); adlength = readLength4(); - data = IOUtils.readFully(this, adlength, true); + data = IOUtils.readExactlyNBytes(this, adlength); auData.add(new AuthorizationDataEntry(adtype, data)); } return auData.toArray(new AuthorizationDataEntry[auData.size()]); @@ -253,7 +253,7 @@ public class CCacheInputStream extends KrbDataInputStream implements FileCCacheC if (length == 0) { return null; } else { - return IOUtils.readFully(this, length, true); + return IOUtils.readExactlyNBytes(this, length); } } diff --git a/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java b/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java index c62e6293ff7484d9328f710f37b819a978118fcb..ccb9b1c0ab825840053dbc134b4cb4ed581cc7cd 100644 --- a/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java +++ b/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java @@ -192,8 +192,9 @@ public class Credentials { // is most likely to be the one in Authenticator in PA-TGS-REQ encoded // in TGS-REQ, therefore only stored with a service ticket. Currently // in Java, we only reads TGTs. - return new sun.security.krb5.Credentials(ticket, - cname, sname, key, flags, authtime, starttime, endtime, renewTill, caddr); + return new sun.security.krb5.Credentials(ticket, cname, null, sname, + null, key, flags, authtime, starttime, endtime, renewTill, + caddr); } public KerberosTime getStartTime() { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java index 83256927e768fbb0c620f4ee7e1f190a1096fe69..b7b06a99d1efe1299b0c65bd23c12b06f90e7937 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -31,10 +31,7 @@ package sun.security.krb5.internal.crypto; -import sun.security.krb5.Config; import sun.security.krb5.Checksum; -import sun.security.krb5.EncryptedData; -import sun.security.krb5.KrbException; import sun.security.krb5.KrbCryptoException; import sun.security.krb5.internal.*; @@ -81,6 +78,7 @@ public abstract class CksumType { cksumTypeName = "sun.security.krb5.internal.crypto.HmacSha1Aes128CksumType"; break; + case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256: cksumType = new HmacSha1Aes256CksumType(); cksumTypeName = @@ -117,32 +115,11 @@ public abstract class CksumType { return cksumType; } - - /** - * Returns default checksum type. - */ - public static CksumType getInstance() throws KdcErrException { - // this method provided for Kerberos applications. - int cksumType = Checksum.CKSUMTYPE_RSA_MD5; // default - try { - Config c = Config.getInstance(); - if ((cksumType = (Config.getType(c.get("libdefaults", - "ap_req_checksum_type")))) == - 1) { - if ((cksumType = Config.getType(c.get("libdefaults", - "checksum_type"))) == -1) { - cksumType = Checksum.CKSUMTYPE_RSA_MD5; // default - } - } - } catch (KrbException e) { - } - return getInstance(cksumType); - } - public abstract int confounderSize(); public abstract int cksumType(); - public abstract boolean isSafe(); + public abstract boolean isKeyed(); public abstract int cksumSize(); @@ -150,13 +127,12 @@ public abstract class CksumType { public abstract int keySize(); - public abstract byte[] calculateChecksum(byte[] data, int size) - throws KrbCryptoException; - - public abstract byte[] calculateKeyedChecksum(byte[] data, int size, + // Note: key and usage will be ignored for an unkeyed checksum. + public abstract byte[] calculateChecksum(byte[] data, int size, byte[] key, int usage) throws KrbCryptoException; - public abstract boolean verifyKeyedChecksum(byte[] data, int size, + // Note: key and usage will be ignored for an unkeyed checksum. + public abstract boolean verifyChecksum(byte[] data, int size, byte[] key, byte[] checksum, int usage) throws KrbCryptoException; public static boolean isChecksumEqual(byte[] cksum1, byte[] cksum2) { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/Crc32CksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/Crc32CksumType.java index b1aa0ab8fbd9aa84febd05277ac271968a74f687..151e2daaa781e63b5218465c2249edbf0b8323ad 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/Crc32CksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/Crc32CksumType.java @@ -32,7 +32,6 @@ package sun.security.krb5.internal.crypto; import sun.security.krb5.*; import sun.security.krb5.internal.*; -import java.util.zip.CRC32; public class Crc32CksumType extends CksumType { @@ -47,7 +46,7 @@ public class Crc32CksumType extends CksumType { return Checksum.CKSUMTYPE_CRC32; } - public boolean isSafe() { + public boolean isKeyed() { return false; } @@ -63,18 +62,15 @@ public class Crc32CksumType extends CksumType { return 0; } - public byte[] calculateChecksum(byte[] data, int size) { + public byte[] calculateChecksum(byte[] data, int size, + byte[] key, int usage) { return crc32.byte2crc32sum_bytes(data, size); } - public byte[] calculateKeyedChecksum(byte[] data, int size, - byte[] key, int usage) { - return null; - } - - public boolean verifyKeyedChecksum(byte[] data, int size, - byte[] key, byte[] checksum, int usage) { - return false; + public boolean verifyChecksum(byte[] data, int size, + byte[] key, byte[] checksum, int usage) { + return CksumType.isChecksumEqual(checksum, + crc32.byte2crc32sum_bytes(data)); } public static byte[] int2quad(long input) { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/DesCbcCrcEType.java b/src/share/classes/sun/security/krb5/internal/crypto/DesCbcCrcEType.java index 08d9d555e3b8da337d51c6d95702928dad6b2818..e930d6a7f13772bc4f074a7b1d2bed2a81eef02b 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/DesCbcCrcEType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/DesCbcCrcEType.java @@ -53,7 +53,7 @@ public class DesCbcCrcEType extends DesCbcEType { } public int checksumType() { - return Checksum.CKSUMTYPE_CRC32; + return Checksum.CKSUMTYPE_RSA_MD5; } public int checksumSize() { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/DesMacCksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/DesMacCksumType.java index 3c3842f59dd1b46c93de54446835acff2b916956..2e11a2042626b10a1878363457193ceda948c914 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/DesMacCksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/DesMacCksumType.java @@ -49,7 +49,7 @@ public class DesMacCksumType extends CksumType { return Checksum.CKSUMTYPE_DES_MAC; } - public boolean isSafe() { + public boolean isKeyed() { return true; } @@ -65,10 +65,6 @@ public class DesMacCksumType extends CksumType { return 8; } - public byte[] calculateChecksum(byte[] data, int size) { - return null; - } - /** * Calculates keyed checksum. * @param data the data used to generate the checksum. @@ -78,7 +74,7 @@ public class DesMacCksumType extends CksumType { * * @modified by Yanni Zhang, 12/08/99. */ - public byte[] calculateKeyedChecksum(byte[] data, int size, byte[] key, + public byte[] calculateChecksum(byte[] data, int size, byte[] key, int usage) throws KrbCryptoException { byte[] new_data = new byte[size + confounderSize()]; byte[] conf = Confounder.bytes(confounderSize()); @@ -130,7 +126,7 @@ public class DesMacCksumType extends CksumType { * * @modified by Yanni Zhang, 12/08/99. */ - public boolean verifyKeyedChecksum(byte[] data, int size, + public boolean verifyChecksum(byte[] data, int size, byte[] key, byte[] checksum, int usage) throws KrbCryptoException { byte[] cksum = decryptKeyedChecksum(checksum, key); diff --git a/src/share/classes/sun/security/krb5/internal/crypto/DesMacKCksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/DesMacKCksumType.java index 805f931e72e8b3cbbebae724be2ae3e0bce9e730..4f706fb8c49475b5d99b1a3c7c69f1541a715f2b 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/DesMacKCksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/DesMacKCksumType.java @@ -48,7 +48,7 @@ public class DesMacKCksumType extends CksumType { return Checksum.CKSUMTYPE_DES_MAC_K; } - public boolean isSafe() { + public boolean isKeyed() { return true; } @@ -64,10 +64,6 @@ public class DesMacKCksumType extends CksumType { return 8; } - public byte[] calculateChecksum(byte[] data, int size) { - return null; - } - /** * Calculates keyed checksum. * @param data the data used to generate the checksum. @@ -77,7 +73,7 @@ public class DesMacKCksumType extends CksumType { * * @modified by Yanni Zhang, 12/08/99. */ - public byte[] calculateKeyedChecksum(byte[] data, int size, byte[] key, + public byte[] calculateChecksum(byte[] data, int size, byte[] key, int usage) throws KrbCryptoException { //check for weak keys try { @@ -93,9 +89,9 @@ public class DesMacKCksumType extends CksumType { return cksum; } - public boolean verifyKeyedChecksum(byte[] data, int size, + public boolean verifyChecksum(byte[] data, int size, byte[] key, byte[] checksum, int usage) throws KrbCryptoException { - byte[] new_cksum = calculateKeyedChecksum(data, data.length, key, usage); + byte[] new_cksum = calculateChecksum(data, data.length, key, usage); return isChecksumEqual(checksum, new_cksum); } diff --git a/src/share/classes/sun/security/krb5/internal/crypto/EType.java b/src/share/classes/sun/security/krb5/internal/crypto/EType.java index feed5d8b96a17e5d43362de1e48b5ca0a23a38d4..ee59d2150753b7eb5f8b4694495ea7bd1b37c0bd 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/EType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/EType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, 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 @@ -301,6 +301,26 @@ public abstract class EType { return isSupported(eTypeConst, enabledETypes); } + /** + * https://tools.ietf.org/html/rfc4120#section-3.1.3: + * + * A "newer" enctype is any enctype first officially + * specified concurrently with or subsequent to the issue of this RFC. + * The enctypes DES, 3DES, or RC4 and any defined in [RFC1510] are not + * "newer" enctypes. + * + * @param eTypeConst the encryption type + * @return true if "newer" + */ + public static boolean isNewer(int eTypeConst) { + return eTypeConst != EncryptedData.ETYPE_DES_CBC_CRC && + eTypeConst != EncryptedData.ETYPE_DES_CBC_MD4 && + eTypeConst != EncryptedData.ETYPE_DES_CBC_MD5 && + eTypeConst != EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD && + eTypeConst != EncryptedData.ETYPE_ARCFOUR_HMAC && + eTypeConst != EncryptedData.ETYPE_ARCFOUR_HMAC_EXP; + } + public static String toString(int type) { switch (type) { case 0: diff --git a/src/share/classes/sun/security/krb5/internal/crypto/HmacMd5ArcFourCksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/HmacMd5ArcFourCksumType.java index 4a233dd803edb9941bf36a9478ed718c5d9cddbc..41388ec87d64b5e39f336614453af721b434d820 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/HmacMd5ArcFourCksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/HmacMd5ArcFourCksumType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, 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 @@ -28,8 +28,6 @@ package sun.security.krb5.internal.crypto; import sun.security.krb5.Checksum; import sun.security.krb5.KrbCryptoException; import sun.security.krb5.internal.*; -import javax.crypto.spec.DESKeySpec; -import java.security.InvalidKeyException; import java.security.GeneralSecurityException; /** @@ -51,7 +49,7 @@ public class HmacMd5ArcFourCksumType extends CksumType { return Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR; } - public boolean isSafe() { + public boolean isKeyed() { return true; } @@ -67,10 +65,6 @@ public class HmacMd5ArcFourCksumType extends CksumType { return 16; // bytes } - public byte[] calculateChecksum(byte[] data, int size) { - return null; - } - /** * Calculates keyed checksum. * @param data the data used to generate the checksum. @@ -78,7 +72,7 @@ public class HmacMd5ArcFourCksumType extends CksumType { * @param key the key used to encrypt the checksum. * @return keyed checksum. */ - public byte[] calculateKeyedChecksum(byte[] data, int size, byte[] key, + public byte[] calculateChecksum(byte[] data, int size, byte[] key, int usage) throws KrbCryptoException { try { @@ -98,7 +92,7 @@ public class HmacMd5ArcFourCksumType extends CksumType { * @param checksum * @return true if verification is successful. */ - public boolean verifyKeyedChecksum(byte[] data, int size, + public boolean verifyChecksum(byte[] data, int size, byte[] key, byte[] checksum, int usage) throws KrbCryptoException { try { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Aes128CksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Aes128CksumType.java index ba31b575dce7ea4a0f1aa935b0313f828beca778..a16941ca050a395be09397a7f275b44dc96952c3 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Aes128CksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Aes128CksumType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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 @@ -28,8 +28,6 @@ package sun.security.krb5.internal.crypto; import sun.security.krb5.Checksum; import sun.security.krb5.KrbCryptoException; import sun.security.krb5.internal.*; -import javax.crypto.spec.DESKeySpec; -import java.security.InvalidKeyException; import java.security.GeneralSecurityException; /* @@ -51,7 +49,7 @@ public class HmacSha1Aes128CksumType extends CksumType { return Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128; } - public boolean isSafe() { + public boolean isKeyed() { return true; } @@ -67,10 +65,6 @@ public class HmacSha1Aes128CksumType extends CksumType { return 16; // bytes } - public byte[] calculateChecksum(byte[] data, int size) { - return null; - } - /** * Calculates keyed checksum. * @param data the data used to generate the checksum. @@ -78,7 +72,7 @@ public class HmacSha1Aes128CksumType extends CksumType { * @param key the key used to encrypt the checksum. * @return keyed checksum. */ - public byte[] calculateKeyedChecksum(byte[] data, int size, byte[] key, + public byte[] calculateChecksum(byte[] data, int size, byte[] key, int usage) throws KrbCryptoException { try { @@ -98,7 +92,7 @@ public class HmacSha1Aes128CksumType extends CksumType { * @param checksum * @return true if verification is successful. */ - public boolean verifyKeyedChecksum(byte[] data, int size, + public boolean verifyChecksum(byte[] data, int size, byte[] key, byte[] checksum, int usage) throws KrbCryptoException { try { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Aes256CksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Aes256CksumType.java index d9f213b0722f31908dab8d638b2a764dc9dea870..9ce9347cc612c4e09b1a232d70453d35fd7ec3f8 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Aes256CksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Aes256CksumType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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 @@ -28,8 +28,6 @@ package sun.security.krb5.internal.crypto; import sun.security.krb5.Checksum; import sun.security.krb5.KrbCryptoException; import sun.security.krb5.internal.*; -import javax.crypto.spec.DESKeySpec; -import java.security.InvalidKeyException; import java.security.GeneralSecurityException; /* @@ -51,7 +49,7 @@ public class HmacSha1Aes256CksumType extends CksumType { return Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256; } - public boolean isSafe() { + public boolean isKeyed() { return true; } @@ -67,10 +65,6 @@ public class HmacSha1Aes256CksumType extends CksumType { return 32; // bytes } - public byte[] calculateChecksum(byte[] data, int size) { - return null; - } - /** * Calculates keyed checksum. * @param data the data used to generate the checksum. @@ -78,7 +72,7 @@ public class HmacSha1Aes256CksumType extends CksumType { * @param key the key used to encrypt the checksum. * @return keyed checksum. */ - public byte[] calculateKeyedChecksum(byte[] data, int size, byte[] key, + public byte[] calculateChecksum(byte[] data, int size, byte[] key, int usage) throws KrbCryptoException { try { @@ -98,7 +92,7 @@ public class HmacSha1Aes256CksumType extends CksumType { * @param checksum * @return true if verification is successful. */ - public boolean verifyKeyedChecksum(byte[] data, int size, + public boolean verifyChecksum(byte[] data, int size, byte[] key, byte[] checksum, int usage) throws KrbCryptoException { try { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Des3KdCksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Des3KdCksumType.java index 9547ea00ae7089e531fac3a848764412fc0ab6db..81e44205eac9d77c0120cb82361f305c298c8374 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Des3KdCksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/HmacSha1Des3KdCksumType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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 @@ -28,8 +28,6 @@ package sun.security.krb5.internal.crypto; import sun.security.krb5.Checksum; import sun.security.krb5.KrbCryptoException; import sun.security.krb5.internal.*; -import javax.crypto.spec.DESKeySpec; -import java.security.InvalidKeyException; import java.security.GeneralSecurityException; public class HmacSha1Des3KdCksumType extends CksumType { @@ -45,7 +43,7 @@ public class HmacSha1Des3KdCksumType extends CksumType { return Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD; } - public boolean isSafe() { + public boolean isKeyed() { return true; } @@ -61,10 +59,6 @@ public class HmacSha1Des3KdCksumType extends CksumType { return 24; // bytes } - public byte[] calculateChecksum(byte[] data, int size) { - return null; - } - /** * Calculates keyed checksum. * @param data the data used to generate the checksum. @@ -72,7 +66,7 @@ public class HmacSha1Des3KdCksumType extends CksumType { * @param key the key used to encrypt the checksum. * @return keyed checksum. */ - public byte[] calculateKeyedChecksum(byte[] data, int size, byte[] key, + public byte[] calculateChecksum(byte[] data, int size, byte[] key, int usage) throws KrbCryptoException { try { @@ -92,7 +86,7 @@ public class HmacSha1Des3KdCksumType extends CksumType { * @param checksum * @return true if verification is successful. */ - public boolean verifyKeyedChecksum(byte[] data, int size, + public boolean verifyChecksum(byte[] data, int size, byte[] key, byte[] checksum, int usage) throws KrbCryptoException { try { diff --git a/src/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java b/src/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java index f9be46c9beb36b7dc77612879f1fd6c97143766d..5179f520024045af4878cd140a38d7ae69d2a864 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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 @@ -56,6 +56,7 @@ public class KeyUsage { public static final int KU_KRB_SAFE_CKSUM = 15; // KrbSafe public static final int KU_PA_FOR_USER_ENC_CKSUM = 17; // S4U2user public static final int KU_AD_KDC_ISSUED_CKSUM = 19; + public static final int KU_AS_REQ = 56; public static final boolean isValid(int usage) { return usage >= 0; diff --git a/src/share/classes/sun/security/krb5/internal/crypto/RsaMd5CksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/RsaMd5CksumType.java index c475749bfab26eea25f5e00a4331b580ba651a4e..e0c4429d7e9a5d337f8eed70aade070261a3c941 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/RsaMd5CksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/RsaMd5CksumType.java @@ -33,8 +33,6 @@ import sun.security.krb5.Checksum; import sun.security.krb5.KrbCryptoException; import sun.security.krb5.internal.*; import java.security.MessageDigest; -import java.security.Provider; -import java.security.Security; public final class RsaMd5CksumType extends CksumType { @@ -49,7 +47,7 @@ public final class RsaMd5CksumType extends CksumType { return Checksum.CKSUMTYPE_RSA_MD5; } - public boolean isSafe() { + public boolean isKeyed() { return false; } @@ -74,7 +72,8 @@ public final class RsaMd5CksumType extends CksumType { * @modified by Yanni Zhang, 12/08/99. */ - public byte[] calculateChecksum(byte[] data, int size) throws KrbCryptoException{ + public byte[] calculateChecksum(byte[] data, int size, + byte[] key, int usage) throws KrbCryptoException{ MessageDigest md5; byte[] result = null; try { @@ -91,14 +90,15 @@ public final class RsaMd5CksumType extends CksumType { return result; } - public byte[] calculateKeyedChecksum(byte[] data, int size, - byte[] key, int usage) throws KrbCryptoException { - return null; - } - - public boolean verifyKeyedChecksum(byte[] data, int size, - byte[] key, byte[] checksum, int usage) throws KrbCryptoException { - return false; + @Override + public boolean verifyChecksum(byte[] data, int size, + byte[] key, byte[] checksum, int usage) + throws KrbCryptoException { + try { + byte[] calculated = MessageDigest.getInstance("MD5").digest(data); + return CksumType.isChecksumEqual(calculated, checksum); + } catch (Exception e) { + return false; + } } - } diff --git a/src/share/classes/sun/security/krb5/internal/crypto/RsaMd5DesCksumType.java b/src/share/classes/sun/security/krb5/internal/crypto/RsaMd5DesCksumType.java index c4c5383316e61ddc4d64fbdff63eadb22319d7ef..0d55aed045acf97483290723ababba4c790cce73 100644 --- a/src/share/classes/sun/security/krb5/internal/crypto/RsaMd5DesCksumType.java +++ b/src/share/classes/sun/security/krb5/internal/crypto/RsaMd5DesCksumType.java @@ -33,12 +33,8 @@ import sun.security.krb5.Checksum; import sun.security.krb5.Confounder; import sun.security.krb5.KrbCryptoException; import sun.security.krb5.internal.*; -import javax.crypto.Cipher; -import javax.crypto.SecretKey; import javax.crypto.spec.DESKeySpec; import java.security.MessageDigest; -import java.security.Provider; -import java.security.Security; import java.security.InvalidKeyException; public final class RsaMd5DesCksumType extends CksumType { @@ -54,7 +50,7 @@ public final class RsaMd5DesCksumType extends CksumType { return Checksum.CKSUMTYPE_RSA_MD5_DES; } - public boolean isSafe() { + public boolean isKeyed() { return true; } @@ -79,7 +75,7 @@ public final class RsaMd5DesCksumType extends CksumType { * * @modified by Yanni Zhang, 12/08/99. */ - public byte[] calculateKeyedChecksum(byte[] data, int size, byte[] key, + public byte[] calculateChecksum(byte[] data, int size, byte[] key, int usage) throws KrbCryptoException { //prepend confounder byte[] new_data = new byte[size + confounderSize()]; @@ -88,7 +84,7 @@ public final class RsaMd5DesCksumType extends CksumType { System.arraycopy(data, 0, new_data, confounderSize(), size); //calculate md5 cksum - byte[] mdc_cksum = calculateChecksum(new_data, new_data.length); + byte[] mdc_cksum = calculateRawChecksum(new_data, new_data.length); byte[] cksum = new byte[cksumSize()]; System.arraycopy(conf, 0, cksum, 0, confounderSize()); System.arraycopy(mdc_cksum, 0, cksum, confounderSize(), @@ -125,7 +121,7 @@ public final class RsaMd5DesCksumType extends CksumType { * * @modified by Yanni Zhang, 12/08/99. */ - public boolean verifyKeyedChecksum(byte[] data, int size, + public boolean verifyChecksum(byte[] data, int size, byte[] key, byte[] checksum, int usage) throws KrbCryptoException { //decrypt checksum byte[] cksum = decryptKeyedChecksum(checksum, key); @@ -135,7 +131,7 @@ public final class RsaMd5DesCksumType extends CksumType { System.arraycopy(cksum, 0, new_data, 0, confounderSize()); System.arraycopy(data, 0, new_data, confounderSize(), size); - byte[] new_cksum = calculateChecksum(new_data, new_data.length); + byte[] new_cksum = calculateRawChecksum(new_data, new_data.length); //extract original cksum value byte[] orig_cksum = new byte[cksumSize() - confounderSize()]; System.arraycopy(cksum, confounderSize(), orig_cksum, 0, @@ -181,7 +177,7 @@ public final class RsaMd5DesCksumType extends CksumType { * * @modified by Yanni Zhang, 12/08/99. */ - public byte[] calculateChecksum(byte[] data, int size) throws KrbCryptoException{ + private byte[] calculateRawChecksum(byte[] data, int size) throws KrbCryptoException{ MessageDigest md5; byte[] result = null; try { @@ -197,5 +193,4 @@ public final class RsaMd5DesCksumType extends CksumType { } return result; } - } diff --git a/src/share/classes/sun/security/provider/JavaKeyStore.java b/src/share/classes/sun/security/provider/JavaKeyStore.java index e3776a42e3adca4b5d2dbf34617327242cb3b7ed..0ed7fa12871e6250f650ba93942e1f0b785c8ab2 100644 --- a/src/share/classes/sun/security/provider/JavaKeyStore.java +++ b/src/share/classes/sun/security/provider/JavaKeyStore.java @@ -694,7 +694,7 @@ abstract class JavaKeyStore extends KeyStoreSpi { // Read the private key entry.protectedPrivKey = - IOUtils.readFully(dis, dis.readInt(), true); + IOUtils.readExactlyNBytes(dis, dis.readInt()); // Read the certificate chain int numOfCerts = dis.readInt(); @@ -719,7 +719,7 @@ abstract class JavaKeyStore extends KeyStoreSpi { } } // instantiate the certificate - encoded = IOUtils.readFully(dis, dis.readInt(), true); + encoded = IOUtils.readExactlyNBytes(dis, dis.readInt()); bais = new ByteArrayInputStream(encoded); certs.add(cf.generateCertificate(bais)); bais.close(); @@ -758,7 +758,7 @@ abstract class JavaKeyStore extends KeyStoreSpi { cfs.put(certType, cf); } } - encoded = IOUtils.readFully(dis, dis.readInt(), true); + encoded = IOUtils.readExactlyNBytes(dis, dis.readInt()); bais = new ByteArrayInputStream(encoded); entry.cert = cf.generateCertificate(bais); bais.close(); @@ -785,16 +785,13 @@ abstract class JavaKeyStore extends KeyStoreSpi { if (password != null) { byte computed[], actual[]; computed = md.digest(); - actual = new byte[computed.length]; - dis.readFully(actual); - for (int i = 0; i < computed.length; i++) { - if (computed[i] != actual[i]) { - Throwable t = new UnrecoverableKeyException + actual = IOUtils.readExactlyNBytes(dis, computed.length); + if (!MessageDigest.isEqual(computed, actual)) { + Throwable t = new UnrecoverableKeyException ("Password verification failed"); - throw (IOException)new IOException + throw (IOException) new IOException ("Keystore was tampered with, or " - + "password was incorrect").initCause(t); - } + + "password was incorrect").initCause(t); } } } diff --git a/src/share/classes/sun/security/provider/SunEntries.java b/src/share/classes/sun/security/provider/SunEntries.java index 9a20f587d935de01c8f9356a96d4dc60059865eb..d856978418a13596cb459c673f5551d7fdf9983e 100644 --- a/src/share/classes/sun/security/provider/SunEntries.java +++ b/src/share/classes/sun/security/provider/SunEntries.java @@ -65,7 +65,7 @@ import sun.security.action.GetPropertyAction; * and CRLs. Aliases for X.509 are X509. * * - PKIX is the certification path validation algorithm described - * in RFC 3280. The ValidationAlgorithm attribute notes the + * in RFC 5280. The ValidationAlgorithm attribute notes the * specification that this provider implements. * * - LDAP is the CertStore type for LDAP repositories. The @@ -266,7 +266,7 @@ final class SunEntries { map.put("CertPathBuilder.PKIX", "sun.security.provider.certpath.SunCertPathBuilder"); map.put("CertPathBuilder.PKIX ValidationAlgorithm", - "RFC3280"); + "RFC5280"); /* * CertPathValidator @@ -274,7 +274,7 @@ final class SunEntries { map.put("CertPathValidator.PKIX", "sun.security.provider.certpath.PKIXCertPathValidator"); map.put("CertPathValidator.PKIX ValidationAlgorithm", - "RFC3280"); + "RFC5280"); /* * CertStores diff --git a/src/share/classes/sun/security/provider/certpath/PolicyChecker.java b/src/share/classes/sun/security/provider/certpath/PolicyChecker.java index ab8282037aa03aa60e9887580cb3f15a775ba617..dd030d3d9db78f706356d6204c44aa9793ffe043 100644 --- a/src/share/classes/sun/security/provider/certpath/PolicyChecker.java +++ b/src/share/classes/sun/security/provider/certpath/PolicyChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -578,7 +578,7 @@ class PolicyChecker extends PKIXCertPathChecker { } /** - * Rewrite leaf nodes at the end of validation as described in RFC 3280 + * Rewrite leaf nodes at the end of validation as described in RFC 5280 * section 6.1.5: Step (g)(iii). Leaf nodes with anyPolicy are replaced * by nodes explicitly representing initial policies not already * represented by leaf nodes. diff --git a/src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java b/src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java index 02109d49d35095da85ba67aade20d99daf9e6bfb..a42a1e8e2731faf5e4c35fadf7eede9a02a1842f 100644 --- a/src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java +++ b/src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -56,7 +56,7 @@ final class PolicyNodeImpl implements PolicyNode { private PolicyNodeImpl mParent; private HashSet mChildren; - // the 4 fields specified by RFC 3280 + // the 4 fields specified by RFC 5280 private String mValidPolicy; private HashSet mQualifierSet; private boolean mCriticalityIndicator; diff --git a/src/share/classes/sun/security/timestamp/HttpTimestamper.java b/src/share/classes/sun/security/timestamp/HttpTimestamper.java index 50cef6ec04b198e614b3344cbe9564da4092ee49..9b646f74b5b9672c20b93cec2357d70dfcfe9597 100644 --- a/src/share/classes/sun/security/timestamp/HttpTimestamper.java +++ b/src/share/classes/sun/security/timestamp/HttpTimestamper.java @@ -27,6 +27,7 @@ package sun.security.timestamp; import java.io.BufferedInputStream; import java.io.DataOutputStream; +import java.io.EOFException; import java.io.IOException; import java.net.URI; import java.net.URL; @@ -147,8 +148,11 @@ public class HttpTimestamper implements Timestamper { } verifyMimeType(connection.getContentType()); - int contentLength = connection.getContentLength(); - replyBuffer = IOUtils.readFully(input, contentLength, false); + int clen = connection.getContentLength(); + replyBuffer = IOUtils.readAllBytes(input); + if (clen != -1 && replyBuffer.length != clen) + throw new EOFException("Expected:" + clen + + ", read:" + replyBuffer.length); if (debug != null) { debug.println("received timestamp response (length=" + diff --git a/src/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java b/src/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java index 0b97cee3745b0911951c124ec480631829e9ba5a..fa05a0d488ba251e13156a839070db10885e5bda 100644 --- a/src/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java +++ b/src/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java @@ -144,7 +144,7 @@ public final class TimestampedSigner extends ContentSigner { /** * Examine the certificate for a Subject Information Access extension - * (RFC 3280). + * (RFC 5280). * The extension's {@code accessMethod} field should contain the object * identifier defined for timestamping: 1.3.6.1.5.5.7.48.3 and its * {@code accessLocation} field should contain an HTTP or HTTPS URL. diff --git a/src/share/classes/sun/security/util/DerInputBuffer.java b/src/share/classes/sun/security/util/DerInputBuffer.java index b09b7b3041108c2382e22320893882165aeef6b6..54eade390441ec8576ccf60ff31f776b5077ccd7 100644 --- a/src/share/classes/sun/security/util/DerInputBuffer.java +++ b/src/share/classes/sun/security/util/DerInputBuffer.java @@ -300,7 +300,7 @@ class DerInputBuffer extends ByteArrayInputStream implements Cloneable { * YYMMDDhhmmss-hhmm * UTC Time is broken in storing only two digits of year. * If YY < 50, we assume 20YY; - * if YY >= 50, we assume 19YY, as per RFC 3280. + * if YY >= 50, we assume 19YY, as per RFC 5280. * * Generalized time has a four-digit year and allows any * precision specified in ISO 8601. However, for our purposes, diff --git a/src/share/classes/sun/security/util/DerOutputStream.java b/src/share/classes/sun/security/util/DerOutputStream.java index c517df8a43ea955c5806fea0a49c90815f2ff7aa..05a7b6346a3ca28b83ab0a0b522f7585931fd2ca 100644 --- a/src/share/classes/sun/security/util/DerOutputStream.java +++ b/src/share/classes/sun/security/util/DerOutputStream.java @@ -461,7 +461,7 @@ extends ByteArrayOutputStream implements DerEncoder { * Marshals a DER UTC time/date value. * *

    YYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time - * and with seconds (even if seconds=0) as per RFC 3280. + * and with seconds (even if seconds=0) as per RFC 5280. */ public void putUTCTime(Date d) throws IOException { putTime(d, DerValue.tag_UtcTime); @@ -471,7 +471,7 @@ extends ByteArrayOutputStream implements DerEncoder { * Marshals a DER Generalized Time/date value. * *

    YYYYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time - * and with seconds (even if seconds=0) as per RFC 3280. + * and with seconds (even if seconds=0) as per RFC 5280. */ public void putGeneralizedTime(Date d) throws IOException { putTime(d, DerValue.tag_GeneralizedTime); diff --git a/src/share/classes/sun/security/util/DerValue.java b/src/share/classes/sun/security/util/DerValue.java index 46dcbd34f387fee4dfbed5f3fd274be6bbb3bb58..9372537375a5010de84d82a4ea7e55e3b84b09ad 100644 --- a/src/share/classes/sun/security/util/DerValue.java +++ b/src/share/classes/sun/security/util/DerValue.java @@ -45,8 +45,8 @@ import sun.misc.IOUtils; * (such as PKCS #10 certificate requests, and some kinds of PKCS #7 data). * * A note with respect to T61/Teletex strings: From RFC 1617, section 4.1.3 - * and RFC 3280, section 4.1.2.4., we assume that this kind of string will - * contain ISO-8859-1 characters only. + * and RFC 5280, section 8, we assume that this kind of string will contain + * ISO-8859-1 characters only. * * * @author David Brownell @@ -409,7 +409,7 @@ public class DerValue { if (fullyBuffered && in.available() != length) throw new IOException("extra data given to DerValue constructor"); - byte[] bytes = IOUtils.readFully(in, length, true); + byte[] bytes = IOUtils.readExactlyNBytes(in, length); buffer = new DerInputBuffer(bytes, allowBER); return new DerInputStream(buffer); diff --git a/src/share/classes/sun/security/validator/PKIXValidator.java b/src/share/classes/sun/security/validator/PKIXValidator.java index 9be502626e6e3d54e229e05c93fe3b2f6f94b01f..d6d973c39de06e723223cfb38c954b00b5bff979 100644 --- a/src/share/classes/sun/security/validator/PKIXValidator.java +++ b/src/share/classes/sun/security/validator/PKIXValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, 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 @@ -32,6 +32,7 @@ import java.security.cert.*; import javax.security.auth.x500.X500Principal; import sun.security.action.GetBooleanAction; +import sun.security.action.GetPropertyAction; import sun.security.provider.certpath.AlgorithmChecker; import sun.security.provider.certpath.PKIXExtendedParameters; @@ -64,6 +65,18 @@ public final class PKIXValidator extends Validator { // enable use of the validator if possible private final static boolean TRY_VALIDATOR = true; + /** + * System property that if set (or set to "true"), allows trust anchor + * certificates to be used if they do not have the proper CA extensions. + * Set to false if prop is not set, or set to any other value. + */ + private static final boolean ALLOW_NON_CA_ANCHOR = allowNonCaAnchor(); + private static boolean allowNonCaAnchor() { + String prop = GetPropertyAction + .privilegedGetProperty("jdk.security.allowNonCaAnchor"); + return prop != null && (prop.isEmpty() || prop.equalsIgnoreCase("true")); + } + private final Set trustedCerts; private final PKIXBuilderParameters parameterTemplate; private int certPathLength = -1; @@ -209,6 +222,7 @@ public final class PKIXValidator extends Validator { ("null or zero-length certificate chain"); } + // Use PKIXExtendedParameters for timestamp and variant additions PKIXBuilderParameters pkixParameters = null; try { @@ -234,29 +248,30 @@ public final class PKIXValidator extends Validator { for (int i = 0; i < chain.length; i++) { X509Certificate cert = chain[i]; X500Principal dn = cert.getSubjectX500Principal(); - if (i != 0 && - !dn.equals(prevIssuer)) { - // chain is not ordered correctly, call builder instead - return doBuild(chain, otherCerts, pkixParameters); - } - // Check if chain[i] is already trusted. It may be inside - // trustedCerts, or has the same dn and public key as a cert - // inside trustedCerts. The latter happens when a CA has - // updated its cert with a stronger signature algorithm in JRE - // but the weak one is still in circulation. - - if (trustedCerts.contains(cert) || // trusted cert - (trustedSubjects.containsKey(dn) && // replacing ... - trustedSubjects.get(dn).contains( // ... weak cert - cert.getPublicKey()))) { - if (i == 0) { + if (i == 0) { + if (trustedCerts.contains(cert)) { return new X509Certificate[] {chain[0]}; } - // Remove and call validator on partial chain [0 .. i-1] - X509Certificate[] newChain = new X509Certificate[i]; - System.arraycopy(chain, 0, newChain, 0, i); - return doValidate(newChain, pkixParameters); + } else { + if (!dn.equals(prevIssuer)) { + // chain is not ordered correctly, call builder instead + return doBuild(chain, otherCerts, pkixParameters); + } + // Check if chain[i] is already trusted. It may be inside + // trustedCerts, or has the same dn and public key as a cert + // inside trustedCerts. The latter happens when a CA has + // updated its cert with a stronger signature algorithm in JRE + // but the weak one is still in circulation. + if (trustedCerts.contains(cert) || // trusted cert + (trustedSubjects.containsKey(dn) && // replacing ... + trustedSubjects.get(dn).contains( // ... weak cert + cert.getPublicKey()))) { + // Remove and call validator on partial chain [0 .. i-1] + X509Certificate[] newChain = new X509Certificate[i]; + System.arraycopy(chain, 0, newChain, 0, i); + return doValidate(newChain, pkixParameters); + } } prevIssuer = cert.getIssuerX500Principal(); } @@ -320,15 +335,18 @@ public final class PKIXValidator extends Validator { private static X509Certificate[] toArray(CertPath path, TrustAnchor anchor) throws CertificateException { - List list = - path.getCertificates(); - X509Certificate[] chain = new X509Certificate[list.size() + 1]; - list.toArray(chain); X509Certificate trustedCert = anchor.getTrustedCert(); if (trustedCert == null) { throw new ValidatorException ("TrustAnchor must be specified as certificate"); } + + verifyTrustAnchor(trustedCert); + + List list = + path.getCertificates(); + X509Certificate[] chain = new X509Certificate[list.size() + 1]; + list.toArray(chain); chain[chain.length - 1] = trustedCert; return chain; } @@ -363,6 +381,41 @@ public final class PKIXValidator extends Validator { } } + /** + * Verify that a trust anchor certificate is a CA certificate. + */ + private static void verifyTrustAnchor(X509Certificate trustedCert) + throws ValidatorException { + + // skip check if jdk.security.allowNonCAAnchor system property is set + if (ALLOW_NON_CA_ANCHOR) { + return; + } + + // allow v1 trust anchor certificates + if (trustedCert.getVersion() < 3) { + return; + } + + // check that the BasicConstraints cA field is not set to false + if (trustedCert.getBasicConstraints() == -1) { + throw new ValidatorException + ("TrustAnchor with subject \"" + + trustedCert.getSubjectX500Principal() + + "\" is not a CA certificate"); + } + + // check that the KeyUsage extension, if included, asserts the + // keyCertSign bit + boolean[] keyUsageBits = trustedCert.getKeyUsage(); + if (keyUsageBits != null && !keyUsageBits[5]) { + throw new ValidatorException + ("TrustAnchor with subject \"" + + trustedCert.getSubjectX500Principal() + + "\" does not have keyCertSign bit set in KeyUsage extension"); + } + } + private X509Certificate[] doBuild(X509Certificate[] chain, Collection otherCerts, PKIXBuilderParameters params) throws CertificateException { diff --git a/src/share/classes/sun/security/x509/AVA.java b/src/share/classes/sun/security/x509/AVA.java index b07e565cfbda40336745fae986361a6b7fad1532..8665745c350b18796fdd8e3667f7eebebcef6278 100644 --- a/src/share/classes/sun/security/x509/AVA.java +++ b/src/share/classes/sun/security/x509/AVA.java @@ -599,7 +599,7 @@ public class AVA implements DerEncoder { if (derval.tag != DerValue.tag_Sequence) { throw new IOException("AVA not a sequence"); } - oid = X500Name.intern(derval.data.getOID()); + oid = derval.data.getOID(); value = derval.data.getDerValue(); if (derval.data.available() != 0) { diff --git a/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java b/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java index 725c753e6509eb0acf22bb47328eba6dfa4b1e03..afc642df2f77ecc7570768fec8b5de164efeca9c 100644 --- a/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java +++ b/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2014, 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 @@ -43,7 +43,7 @@ import sun.security.util.DerValue; * certificate that identifies the specific OCSP Responder to use when * performing on-line validation of that certificate. *

    - * This extension is defined in + * This extension is defined in * Internet X.509 PKI Certificate and Certificate Revocation List * (CRL) Profile. The profile permits * the extension to be included in end-entity or CA certificates, diff --git a/src/share/classes/sun/security/x509/CertificateIssuerExtension.java b/src/share/classes/sun/security/x509/CertificateIssuerExtension.java index b7739707ddf146a94ef311221e4d398e0258339d..0dd8f39642a3bb87c7234992df95a9e5cd6fb693 100644 --- a/src/share/classes/sun/security/x509/CertificateIssuerExtension.java +++ b/src/share/classes/sun/security/x509/CertificateIssuerExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -44,7 +44,7 @@ import sun.security.util.DerOutputStream; *

    * If used by conforming CRL issuers, this extension is always * critical. If an implementation ignored this extension it could not - * correctly attribute CRL entries to certificates. PKIX (RFC 3280) + * correctly attribute CRL entries to certificates. PKIX (RFC 5280) * RECOMMENDS that implementations recognize this extension. *

    * The ASN.1 definition for this is: diff --git a/src/share/classes/sun/security/x509/DeltaCRLIndicatorExtension.java b/src/share/classes/sun/security/x509/DeltaCRLIndicatorExtension.java index 69be1457c000d8feb865c2fda8a118c0bc00b5ea..4b032239398bf0ab186fcced70af073e2f5131cf 100644 --- a/src/share/classes/sun/security/x509/DeltaCRLIndicatorExtension.java +++ b/src/share/classes/sun/security/x509/DeltaCRLIndicatorExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -45,7 +45,7 @@ import sun.security.util.*; * *

    * The extension is defined in Section 5.2.4 of - * Internet X.509 PKI Certific + * Internet X.509 PKI Certific ate and Certificate Revocation List (CRL) Profile. * *

    diff --git a/src/share/classes/sun/security/x509/ExtendedKeyUsageExtension.java b/src/share/classes/sun/security/x509/ExtendedKeyUsageExtension.java index 680846029bd0b1ccacccee1eb2cc2fe4cd703f9b..dc820770ef8ab5107f42d941a880c1d84d2710d3 100644 --- a/src/share/classes/sun/security/x509/ExtendedKeyUsageExtension.java +++ b/src/share/classes/sun/security/x509/ExtendedKeyUsageExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -94,7 +94,7 @@ implements CertAttrSet { public static final String NAME = "ExtendedKeyUsage"; public static final String USAGES = "usages"; - // OID defined in RFC 3280 Sections 4.2.1.13 + // OID defined in RFC 5280 Sections 4.2.1.12 // more from http://www.alvestrand.no/objectid/1.3.6.1.5.5.7.3.html private static final Map map = new HashMap (); diff --git a/src/share/classes/sun/security/x509/FreshestCRLExtension.java b/src/share/classes/sun/security/x509/FreshestCRLExtension.java index 775e2ac0329e4d50c40d226c1c11ddc6aa5f10c0..3d0723da5bf9041d030b3304303d3cbad44990b4 100644 --- a/src/share/classes/sun/security/x509/FreshestCRLExtension.java +++ b/src/share/classes/sun/security/x509/FreshestCRLExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -42,7 +42,7 @@ import sun.security.util.*; * *

    * The extension is defined in Section 5.2.6 of - * Internet X.509 PKI Certific + * Internet X.509 PKI Certific ate and Certificate Revocation List (CRL) Profile. * *

    diff --git a/src/share/classes/sun/security/x509/InvalidityDateExtension.java b/src/share/classes/sun/security/x509/InvalidityDateExtension.java index eda0216489ec3a1d720a76fbb5dda743b328e675..7fac65f3ee592c28fe608e27a01c212433bb86f9 100644 --- a/src/share/classes/sun/security/x509/InvalidityDateExtension.java +++ b/src/share/classes/sun/security/x509/InvalidityDateExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2014, 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 @@ -33,7 +33,7 @@ import java.util.Enumeration; import sun.security.util.*; /** - * From RFC 3280: + * From RFC 5280: *

    * The invalidity date is a non-critical CRL entry extension that * provides the date on which it is known or suspected that the private diff --git a/src/share/classes/sun/security/x509/IssuingDistributionPointExtension.java b/src/share/classes/sun/security/x509/IssuingDistributionPointExtension.java index 6fe8eb3b13c6f4185585f8451e8b7b1ac0852cb0..6866af0830930f0c209dbc94318afb25c6ee17df 100644 --- a/src/share/classes/sun/security/x509/IssuingDistributionPointExtension.java +++ b/src/share/classes/sun/security/x509/IssuingDistributionPointExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -46,7 +46,7 @@ import sun.security.util.DerValue; * *

    * The extension is defined in Section 5.2.5 of - * Internet X.509 PKI Certific + * Internet X.509 PKI Certific ate and Certificate Revocation List (CRL) Profile. * *

    diff --git a/src/share/classes/sun/security/x509/RDN.java b/src/share/classes/sun/security/x509/RDN.java index e60e2e8435449ee5b2d5e9e636bfd3af5a5a18fc..9eb60681fa5936fba9e99ddd6acfacc14682deff 100644 --- a/src/share/classes/sun/security/x509/RDN.java +++ b/src/share/classes/sun/security/x509/RDN.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2014, 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 @@ -343,7 +343,7 @@ public class RDN { /* * Returns a printable form of this RDN, using RFC 1779 style catenation * of attribute/value assertions, and emitting attribute type keywords - * from RFCs 1779, 2253, and 3280. + * from RFCs 1779, 2253, and 5280. */ public String toString() { if (assertion.length == 1) { diff --git a/src/share/classes/sun/security/x509/README b/src/share/classes/sun/security/x509/README index 31a129186599297242b38aec1023ba2c0ba1fdad..f18a37352398babe1c7312beaf1a0193fd4a731c 100644 --- a/src/share/classes/sun/security/x509/README +++ b/src/share/classes/sun/security/x509/README @@ -34,7 +34,7 @@ found in: Protocol (LDAP) that many organizations are expecting will help address online certificate distribution over the Internet. - RFC 3280, which describes the Internet X.509 Public Key + RFC 5280, which describes the Internet X.509 Public Key Infrastructure Certificate and CRL Profile. RSA DSI has a bunch of "Public Key Cryptography Standards" (PKCS) which diff --git a/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java b/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java index e1a0bc2611468ef4b2b65b667219de99d99602dd..29d60eff84e04cea95f1245a08661c17587817f4 100644 --- a/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java +++ b/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2014, 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 @@ -48,7 +48,7 @@ import sun.security.util.DerValue; * included in end entity or CA certificates. Conforming CAs MUST mark * this extension as non-critical. *

    - * This extension is defined in + * This extension is defined in * Internet X.509 PKI Certificate and Certificate Revocation List * (CRL) Profile. The profile permits * the extension to be included in end-entity or CA certificates, diff --git a/src/share/classes/sun/security/x509/URIName.java b/src/share/classes/sun/security/x509/URIName.java index 3c5b523b5f07414ca32b9051d89ac3535066e65e..2d2cafd21ec553d38bb6d381154a7f8d51cde55a 100644 --- a/src/share/classes/sun/security/x509/URIName.java +++ b/src/share/classes/sun/security/x509/URIName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -35,15 +35,15 @@ import sun.security.util.*; * This class implements the URIName as required by the GeneralNames * ASN.1 object. *

    - * [RFC3280] When the subjectAltName extension contains a URI, the name MUST be + * [RFC5280] When the subjectAltName extension contains a URI, the name MUST be * stored in the uniformResourceIdentifier (an IA5String). The name MUST * be a non-relative URL, and MUST follow the URL syntax and encoding - * rules specified in [RFC 1738]. The name must include both a scheme + * rules specified in [RFC 3986]. The name must include both a scheme * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme- * specific-part must include a fully qualified domain name or IP * address as the host. *

    - * As specified in [RFC 1738], the scheme name is not case-sensitive + * As specified in [RFC 3986], the scheme name is not case-sensitive * (e.g., "http" is equivalent to "HTTP"). The host part is also not * case-sensitive, but other components of the scheme-specific-part may * be case-sensitive. When comparing URIs, conforming implementations @@ -113,7 +113,7 @@ public class URIName implements GeneralNameInterface { } host = uri.getHost(); - // RFC 3280 says that the host should be non-null, but we allow it to + // RFC 5280 says that the host should be non-null, but we allow it to // be null because some widely deployed certificates contain CDP // extensions with URIs that have no hostname (see bugs 4802236 and // 5107944). @@ -148,7 +148,7 @@ public class URIName implements GeneralNameInterface { /** * Create the URIName object with the specified name constraint. URI * name constraints syntax is different than SubjectAltNames, etc. See - * 4.2.1.11 of RFC 3280. + * 4.2.1.10 of RFC 5280. * * @param value the URI name constraint * @throws IOException if name is not a proper URI name constraint @@ -300,7 +300,7 @@ public class URIName implements GeneralNameInterface { * These results are used in checking NameConstraints during * certification path verification. *

    - * RFC3280: For URIs, the constraint applies to the host part of the name. + * RFC5280: For URIs, the constraint applies to the host part of the name. * The constraint may specify a host or a domain. Examples would be * "foo.bar.com"; and ".xyz.com". When the the constraint begins with * a period, it may be expanded with one or more subdomains. That is, diff --git a/src/share/classes/sun/security/x509/X500Name.java b/src/share/classes/sun/security/x509/X500Name.java index 447395c503faf860527e2e1f8f84320c501ed4ad..f70c00fe26a095d0e527c3d27085298556ee8e0f 100644 --- a/src/share/classes/sun/security/x509/X500Name.java +++ b/src/share/classes/sun/security/x509/X500Name.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, 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 @@ -604,7 +604,7 @@ public class X500Name implements GeneralNameInterface, Principal { * Returns a string form of the X.500 distinguished name. * The format of the string is from RFC 1779. The returned string * may contain non-standardised keywords for more readability - * (keywords from RFCs 1779, 2253, and 3280). + * (keywords from RFCs 1779, 2253, and 5280). */ public String toString() { if (dn == null) { @@ -865,7 +865,7 @@ public class X500Name implements GeneralNameInterface, Principal { * O="Sue, Grabbit and Runn" or * O=Sue\, Grabbit and Runn * - * This method can parse RFC 1779, 2253 or 4514 DNs and non-standard 3280 + * This method can parse RFC 1779, 2253 or 4514 DNs and non-standard 5280 * keywords. Additional keywords can be specified in the keyword/OID map. */ private void parseDN(String input, Map keywordMap) @@ -1103,21 +1103,9 @@ public class X500Name implements GeneralNameInterface, Principal { /****************************************************************/ - /* - * Maybe return a preallocated OID, to reduce storage costs - * and speed recognition of common X.500 attributes. - */ - static ObjectIdentifier intern(ObjectIdentifier oid) { - ObjectIdentifier interned = internedOIDs.putIfAbsent(oid, oid); - return (interned == null) ? oid : interned; - } - - private static final Map internedOIDs - = new HashMap(); - /* * Selected OIDs from X.520 - * Includes all those specified in RFC 3280 as MUST or SHOULD + * Includes all those specified in RFC 5280 as MUST or SHOULD * be recognized */ private static final int commonName_data[] = { 2, 5, 4, 3 }; @@ -1142,92 +1130,82 @@ public class X500Name implements GeneralNameInterface, Principal { { 0, 9, 2342, 19200300, 100, 1, 1 }; - public static final ObjectIdentifier commonName_oid; - public static final ObjectIdentifier countryName_oid; - public static final ObjectIdentifier localityName_oid; - public static final ObjectIdentifier orgName_oid; - public static final ObjectIdentifier orgUnitName_oid; - public static final ObjectIdentifier stateName_oid; - public static final ObjectIdentifier streetAddress_oid; - public static final ObjectIdentifier title_oid; - public static final ObjectIdentifier DNQUALIFIER_OID; - public static final ObjectIdentifier SURNAME_OID; - public static final ObjectIdentifier GIVENNAME_OID; - public static final ObjectIdentifier INITIALS_OID; - public static final ObjectIdentifier GENERATIONQUALIFIER_OID; - public static final ObjectIdentifier ipAddress_oid; - public static final ObjectIdentifier DOMAIN_COMPONENT_OID; - public static final ObjectIdentifier userid_oid; - public static final ObjectIdentifier SERIALNUMBER_OID; - - static { - /** OID for the "CN=" attribute, denoting a person's common name. */ - commonName_oid = intern(ObjectIdentifier.newInternal(commonName_data)); - - /** OID for the "SERIALNUMBER=" attribute, denoting a serial number for. - a name. Do not confuse with PKCS#9 issuerAndSerialNumber or the - certificate serial number. */ - SERIALNUMBER_OID = intern(ObjectIdentifier.newInternal(SERIALNUMBER_DATA)); - - /** OID for the "C=" attribute, denoting a country. */ - countryName_oid = intern(ObjectIdentifier.newInternal(countryName_data)); - - /** OID for the "L=" attribute, denoting a locality (such as a city) */ - localityName_oid = intern(ObjectIdentifier.newInternal(localityName_data)); - - /** OID for the "O=" attribute, denoting an organization name */ - orgName_oid = intern(ObjectIdentifier.newInternal(orgName_data)); - - /** OID for the "OU=" attribute, denoting an organizational unit name */ - orgUnitName_oid = intern(ObjectIdentifier.newInternal(orgUnitName_data)); - - /** OID for the "S=" attribute, denoting a state (such as Delaware) */ - stateName_oid = intern(ObjectIdentifier.newInternal(stateName_data)); - - /** OID for the "STREET=" attribute, denoting a street address. */ - streetAddress_oid = intern(ObjectIdentifier.newInternal(streetAddress_data)); - - /** OID for the "T=" attribute, denoting a person's title. */ - title_oid = intern(ObjectIdentifier.newInternal(title_data)); - - /** OID for the "DNQUALIFIER=" or "DNQ=" attribute, denoting DN - disambiguating information.*/ - DNQUALIFIER_OID = intern(ObjectIdentifier.newInternal(DNQUALIFIER_DATA)); - - /** OID for the "SURNAME=" attribute, denoting a person's surname.*/ - SURNAME_OID = intern(ObjectIdentifier.newInternal(SURNAME_DATA)); - - /** OID for the "GIVENNAME=" attribute, denoting a person's given name.*/ - GIVENNAME_OID = intern(ObjectIdentifier.newInternal(GIVENNAME_DATA)); - - /** OID for the "INITIALS=" attribute, denoting a person's initials.*/ - INITIALS_OID = intern(ObjectIdentifier.newInternal(INITIALS_DATA)); - - /** OID for the "GENERATION=" attribute, denoting Jr., II, etc.*/ - GENERATIONQUALIFIER_OID = - intern(ObjectIdentifier.newInternal(GENERATIONQUALIFIER_DATA)); - - /* - * OIDs from other sources which show up in X.500 names we - * expect to deal with often - */ - /** OID for "IP=" IP address attributes, used with SKIP. */ - ipAddress_oid = intern(ObjectIdentifier.newInternal(ipAddress_data)); - - /* - * Domain component OID from RFC 1274, RFC 2247, RFC 3280 - */ - - /* - * OID for "DC=" domain component attributes, used with DNSNames in DN - * format - */ - DOMAIN_COMPONENT_OID = - intern(ObjectIdentifier.newInternal(DOMAIN_COMPONENT_DATA)); - - /** OID for "UID=" denoting a user id, defined in RFCs 1274 & 2798. */ - userid_oid = intern(ObjectIdentifier.newInternal(userid_data)); - } + // OID for the "CN=" attribute, denoting a person's common name. + public static final ObjectIdentifier commonName_oid = + ObjectIdentifier.newInternal(commonName_data); + + // OID for the "SERIALNUMBER=" attribute, denoting a serial number for. + // a name. Do not confuse with PKCS#9 issuerAndSerialNumber or the + // certificate serial number. + public static final ObjectIdentifier SERIALNUMBER_OID = + ObjectIdentifier.newInternal(SERIALNUMBER_DATA); + + // OID for the "C=" attribute, denoting a country. + public static final ObjectIdentifier countryName_oid = + ObjectIdentifier.newInternal(countryName_data); + + // OID for the "L=" attribute, denoting a locality (such as a city). + public static final ObjectIdentifier localityName_oid = + ObjectIdentifier.newInternal(localityName_data); + + // OID for the "O=" attribute, denoting an organization name. + public static final ObjectIdentifier orgName_oid = + ObjectIdentifier.newInternal(orgName_data); + + // OID for the "OU=" attribute, denoting an organizational unit name. + public static final ObjectIdentifier orgUnitName_oid = + ObjectIdentifier.newInternal(orgUnitName_data); + + // OID for the "S=" attribute, denoting a state (such as Delaware). + public static final ObjectIdentifier stateName_oid = + ObjectIdentifier.newInternal(stateName_data); + + // OID for the "STREET=" attribute, denoting a street address. + public static final ObjectIdentifier streetAddress_oid = + ObjectIdentifier.newInternal(streetAddress_data); + + // OID for the "T=" attribute, denoting a person's title. + public static final ObjectIdentifier title_oid = + ObjectIdentifier.newInternal(title_data); + + // OID for the "DNQUALIFIER=" or "DNQ=" attribute, denoting DN + // disambiguating information. + public static final ObjectIdentifier DNQUALIFIER_OID = + ObjectIdentifier.newInternal(DNQUALIFIER_DATA); + + // OID for the "SURNAME=" attribute, denoting a person's surname. + public static final ObjectIdentifier SURNAME_OID = + ObjectIdentifier.newInternal(SURNAME_DATA); + + // OID for the "GIVENNAME=" attribute, denoting a person's given name. + public static final ObjectIdentifier GIVENNAME_OID = + ObjectIdentifier.newInternal(GIVENNAME_DATA); + + // OID for the "INITIALS=" attribute, denoting a person's initials. + public static final ObjectIdentifier INITIALS_OID = + ObjectIdentifier.newInternal(INITIALS_DATA); + + // OID for the "GENERATION=" attribute, denoting Jr., II, etc. + public static final ObjectIdentifier GENERATIONQUALIFIER_OID = + ObjectIdentifier.newInternal(GENERATIONQUALIFIER_DATA); + + // OIDs from other sources which show up in X.500 names we + // expect to deal with often. + // + // OID for "IP=" IP address attributes, used with SKIP. + public static final ObjectIdentifier ipAddress_oid = + ObjectIdentifier.newInternal(ipAddress_data); + + // Domain component OID from RFC 1274, RFC 2247, RFC 5280. + // + // OID for "DC=" domain component attributes, used with DNSNames in DN + // format. + public static final ObjectIdentifier DOMAIN_COMPONENT_OID = + ObjectIdentifier.newInternal(DOMAIN_COMPONENT_DATA); + + // OID for "UID=" denoting a user id, defined in RFCs 1274 & 2798. + public static final ObjectIdentifier userid_oid = + ObjectIdentifier.newInternal(userid_data); /** * Return constraint type:

      diff --git a/src/share/classes/sun/security/x509/X509CRLImpl.java b/src/share/classes/sun/security/x509/X509CRLImpl.java index 12bd5af03e3ff0b411462bdd2cadcb0305db39e8..abc6d7264ad54e41c9d46a26884de7f0627a303d 100644 --- a/src/share/classes/sun/security/x509/X509CRLImpl.java +++ b/src/share/classes/sun/security/x509/X509CRLImpl.java @@ -55,7 +55,7 @@ import sun.misc.HexDumpEncoder; * signature BIT STRING } * * More information can be found in - * RFC 3280: Internet X.509 + * RFC 5280: Internet X.509 * Public Key Infrastructure Certificate and CRL Profile. *

      * The ASN.1 definition of tbsCertList is: diff --git a/src/share/classes/sun/security/x509/X509CertInfo.java b/src/share/classes/sun/security/x509/X509CertInfo.java index b7f2dd85bcd108a6543c76ca202caf657bad5336..fa64e9d0fc219ab12435649675f9a5a198d499b9 100644 --- a/src/share/classes/sun/security/x509/X509CertInfo.java +++ b/src/share/classes/sun/security/x509/X509CertInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -708,7 +708,7 @@ public class X509CertInfo implements CertAttrSet { } /* - * Verify if X.509 V3 Certificate is compliant with RFC 3280. + * Verify if X.509 V3 Certificate is compliant with RFC 5280. */ private void verifyCert(X500Name subject, CertificateExtensions extensions) diff --git a/src/share/lib/security/java.security-aix b/src/share/lib/security/java.security-aix index e73f6e14894ef117e03cd68dd83a6b37cbf8512d..7f20467244f17bfcbe85c0a78a730e9d9237e823 100644 --- a/src/share/lib/security/java.security-aix +++ b/src/share/lib/security/java.security-aix @@ -341,7 +341,7 @@ networkaddress.cache.negative.ttl=10 # By default, the location of the OCSP responder is determined implicitly # from the certificate being validated. This property explicitly specifies # the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent +# Authority Information Access extension (defined in RFC 5280) is absent # from the certificate or when it requires overriding. # # Example, @@ -420,6 +420,32 @@ networkaddress.cache.negative.ttl=10 # krb5.kdc.bad.policy = tryLess:2,2000 krb5.kdc.bad.policy = tryLast +# +# Kerberos cross-realm referrals (RFC 6806) +# +# OpenJDK's Kerberos client supports cross-realm referrals as defined in +# RFC 6806. This allows to setup more dynamic environments in which clients +# do not need to know in advance how to reach the realm of a target principal +# (either a user or service). +# +# When a client issues an AS or a TGS request, the "canonicalize" option +# is set to announce support of this feature. A KDC server may fulfill the +# request or reply referring the client to a different one. If referred, +# the client will issue a new request and the cycle repeats. +# +# In addition to referrals, the "canonicalize" option allows the KDC server +# to change the client name in response to an AS request. For security reasons, +# RFC 6806 (section 11) FAST scheme is enforced. +# +# Disable Kerberos cross-realm referrals. Value may be overwritten with a +# System property (-Dsun.security.krb5.disableReferrals). +sun.security.krb5.disableReferrals=false + +# Maximum number of AS or TGS referrals to avoid infinite loops. Value may +# be overwritten with a System property (-Dsun.security.krb5.maxReferrals). +sun.security.krb5.maxReferrals=5 + +# # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable @@ -860,8 +886,8 @@ jdk.xml.dsig.secureValidationPolicy=\ # Patterns are separated by ";" (semicolon). # Whitespace is significant and is considered part of the pattern. # -# If the system property jdk.serialFilter is also specified, it supersedes -# the security property value defined here. +# If the system property jdk.serialFilter is also specified on the command +# line, it supersedes the security property value defined here. # # If a pattern includes a "=", it sets a limit. # If a limit appears more than once the last value is used. diff --git a/src/share/lib/security/java.security-linux b/src/share/lib/security/java.security-linux index 4fe5c0f5da02ca7674163d5c4fd35d6b0fcc4d1f..a866a05767f69023e770a53a3795f00f49ad4b02 100644 --- a/src/share/lib/security/java.security-linux +++ b/src/share/lib/security/java.security-linux @@ -341,7 +341,7 @@ networkaddress.cache.negative.ttl=10 # By default, the location of the OCSP responder is determined implicitly # from the certificate being validated. This property explicitly specifies # the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent +# Authority Information Access extension (defined in RFC 5280) is absent # from the certificate or when it requires overriding. # # Example, @@ -420,6 +420,32 @@ networkaddress.cache.negative.ttl=10 # krb5.kdc.bad.policy = tryLess:2,2000 krb5.kdc.bad.policy = tryLast +# +# Kerberos cross-realm referrals (RFC 6806) +# +# OpenJDK's Kerberos client supports cross-realm referrals as defined in +# RFC 6806. This allows to setup more dynamic environments in which clients +# do not need to know in advance how to reach the realm of a target principal +# (either a user or service). +# +# When a client issues an AS or a TGS request, the "canonicalize" option +# is set to announce support of this feature. A KDC server may fulfill the +# request or reply referring the client to a different one. If referred, +# the client will issue a new request and the cycle repeats. +# +# In addition to referrals, the "canonicalize" option allows the KDC server +# to change the client name in response to an AS request. For security reasons, +# RFC 6806 (section 11) FAST scheme is enforced. +# +# Disable Kerberos cross-realm referrals. Value may be overwritten with a +# System property (-Dsun.security.krb5.disableReferrals). +sun.security.krb5.disableReferrals=false + +# Maximum number of AS or TGS referrals to avoid infinite loops. Value may +# be overwritten with a System property (-Dsun.security.krb5.maxReferrals). +sun.security.krb5.maxReferrals=5 + +# # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable @@ -861,8 +887,8 @@ jdk.xml.dsig.secureValidationPolicy=\ # Patterns are separated by ";" (semicolon). # Whitespace is significant and is considered part of the pattern. # -# If the system property jdk.serialFilter is also specified, it supersedes -# the security property value defined here. +# If the system property jdk.serialFilter is also specified on the command +# line, it supersedes the security property value defined here. # # If a pattern includes a "=", it sets a limit. # If a limit appears more than once the last value is used. diff --git a/src/share/lib/security/java.security-macosx b/src/share/lib/security/java.security-macosx index c539c0cf7ce287a7a6c29e9c58ffe6a3afb3092a..9726d39413f5ba937405571d3bd443ca293435ef 100644 --- a/src/share/lib/security/java.security-macosx +++ b/src/share/lib/security/java.security-macosx @@ -344,7 +344,7 @@ networkaddress.cache.negative.ttl=10 # By default, the location of the OCSP responder is determined implicitly # from the certificate being validated. This property explicitly specifies # the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent +# Authority Information Access extension (defined in RFC 5280) is absent # from the certificate or when it requires overriding. # # Example, @@ -423,6 +423,32 @@ networkaddress.cache.negative.ttl=10 # krb5.kdc.bad.policy = tryLess:2,2000 krb5.kdc.bad.policy = tryLast +# +# Kerberos cross-realm referrals (RFC 6806) +# +# OpenJDK's Kerberos client supports cross-realm referrals as defined in +# RFC 6806. This allows to setup more dynamic environments in which clients +# do not need to know in advance how to reach the realm of a target principal +# (either a user or service). +# +# When a client issues an AS or a TGS request, the "canonicalize" option +# is set to announce support of this feature. A KDC server may fulfill the +# request or reply referring the client to a different one. If referred, +# the client will issue a new request and the cycle repeats. +# +# In addition to referrals, the "canonicalize" option allows the KDC server +# to change the client name in response to an AS request. For security reasons, +# RFC 6806 (section 11) FAST scheme is enforced. +# +# Disable Kerberos cross-realm referrals. Value may be overwritten with a +# System property (-Dsun.security.krb5.disableReferrals). +sun.security.krb5.disableReferrals=false + +# Maximum number of AS or TGS referrals to avoid infinite loops. Value may +# be overwritten with a System property (-Dsun.security.krb5.maxReferrals). +sun.security.krb5.maxReferrals=5 + +# # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable @@ -864,8 +890,8 @@ jdk.xml.dsig.secureValidationPolicy=\ # Patterns are separated by ";" (semicolon). # Whitespace is significant and is considered part of the pattern. # -# If the system property jdk.serialFilter is also specified, it supersedes -# the security property value defined here. +# If the system property jdk.serialFilter is also specified on the command +# line, it supersedes the security property value defined here. # # If a pattern includes a "=", it sets a limit. # If a limit appears more than once the last value is used. diff --git a/src/share/lib/security/java.security-solaris b/src/share/lib/security/java.security-solaris index 101f8c34efce66eac543791b9738bc03152427b6..f50b9feebf39030091c8ce0fc5eba24ed596ad46 100644 --- a/src/share/lib/security/java.security-solaris +++ b/src/share/lib/security/java.security-solaris @@ -343,7 +343,7 @@ networkaddress.cache.negative.ttl=10 # By default, the location of the OCSP responder is determined implicitly # from the certificate being validated. This property explicitly specifies # the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent +# Authority Information Access extension (defined in RFC 5280) is absent # from the certificate or when it requires overriding. # # Example, @@ -422,6 +422,32 @@ networkaddress.cache.negative.ttl=10 # krb5.kdc.bad.policy = tryLess:2,2000 krb5.kdc.bad.policy = tryLast +# +# Kerberos cross-realm referrals (RFC 6806) +# +# OpenJDK's Kerberos client supports cross-realm referrals as defined in +# RFC 6806. This allows to setup more dynamic environments in which clients +# do not need to know in advance how to reach the realm of a target principal +# (either a user or service). +# +# When a client issues an AS or a TGS request, the "canonicalize" option +# is set to announce support of this feature. A KDC server may fulfill the +# request or reply referring the client to a different one. If referred, +# the client will issue a new request and the cycle repeats. +# +# In addition to referrals, the "canonicalize" option allows the KDC server +# to change the client name in response to an AS request. For security reasons, +# RFC 6806 (section 11) FAST scheme is enforced. +# +# Disable Kerberos cross-realm referrals. Value may be overwritten with a +# System property (-Dsun.security.krb5.disableReferrals). +sun.security.krb5.disableReferrals=false + +# Maximum number of AS or TGS referrals to avoid infinite loops. Value may +# be overwritten with a System property (-Dsun.security.krb5.maxReferrals). +sun.security.krb5.maxReferrals=5 + +# # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable @@ -863,8 +889,8 @@ jdk.xml.dsig.secureValidationPolicy=\ # Patterns are separated by ";" (semicolon). # Whitespace is significant and is considered part of the pattern. # -# If the system property jdk.serialFilter is also specified, it supersedes -# the security property value defined here. +# If the system property jdk.serialFilter is also specified on the command +# line, it supersedes the security property value defined here. # # If a pattern includes a "=", it sets a limit. # If a limit appears more than once the last value is used. diff --git a/src/share/lib/security/java.security-windows b/src/share/lib/security/java.security-windows index 609cd7cb1197135da259c3a52e457275c04eaecd..dd66f694122e37b29d65ed296aa2c990d8e705a0 100644 --- a/src/share/lib/security/java.security-windows +++ b/src/share/lib/security/java.security-windows @@ -344,7 +344,7 @@ networkaddress.cache.negative.ttl=10 # By default, the location of the OCSP responder is determined implicitly # from the certificate being validated. This property explicitly specifies # the location of the OCSP responder. The property is used when the -# Authority Information Access extension (defined in RFC 3280) is absent +# Authority Information Access extension (defined in RFC 5280) is absent # from the certificate or when it requires overriding. # # Example, @@ -423,6 +423,32 @@ networkaddress.cache.negative.ttl=10 # krb5.kdc.bad.policy = tryLess:2,2000 krb5.kdc.bad.policy = tryLast +# +# Kerberos cross-realm referrals (RFC 6806) +# +# OpenJDK's Kerberos client supports cross-realm referrals as defined in +# RFC 6806. This allows to setup more dynamic environments in which clients +# do not need to know in advance how to reach the realm of a target principal +# (either a user or service). +# +# When a client issues an AS or a TGS request, the "canonicalize" option +# is set to announce support of this feature. A KDC server may fulfill the +# request or reply referring the client to a different one. If referred, +# the client will issue a new request and the cycle repeats. +# +# In addition to referrals, the "canonicalize" option allows the KDC server +# to change the client name in response to an AS request. For security reasons, +# RFC 6806 (section 11) FAST scheme is enforced. +# +# Disable Kerberos cross-realm referrals. Value may be overwritten with a +# System property (-Dsun.security.krb5.disableReferrals). +sun.security.krb5.disableReferrals=false + +# Maximum number of AS or TGS referrals to avoid infinite loops. Value may +# be overwritten with a System property (-Dsun.security.krb5.maxReferrals). +sun.security.krb5.maxReferrals=5 + +# # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable @@ -864,8 +890,8 @@ jdk.xml.dsig.secureValidationPolicy=\ # Patterns are separated by ";" (semicolon). # Whitespace is significant and is considered part of the pattern. # -# If the system property jdk.serialFilter is also specified, it supersedes -# the security property value defined here. +# If the system property jdk.serialFilter is also specified on the command +# line, it supersedes the security property value defined here. # # If a pattern includes a "=", it sets a limit. # If a limit appears more than once the last value is used. diff --git a/src/share/native/sun/font/freetypeScaler.c b/src/share/native/sun/font/freetypeScaler.c index 228a4f98f0e636bbea0b176f10779289466d64dd..30f34e4c2736771cae7fbce6e46d9b7707d4d5b9 100644 --- a/src/share/native/sun/font/freetypeScaler.c +++ b/src/share/native/sun/font/freetypeScaler.c @@ -675,10 +675,14 @@ Java_sun_font_FreetypeFontScaler_getGlyphMetricsNative( pScalerContext, pScaler, glyphCode); info = (GlyphInfo*) jlong_to_ptr(image); - (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, info->advanceX); - (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, info->advanceY); - - free(info); + if (info != NULL) { + (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, info->advanceX); + (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, info->advanceY); + free(info); + } else { + (*env)->SetFloatField(env, metrics, sunFontIDs.xFID, 0.0f); + (*env)->SetFloatField(env, metrics, sunFontIDs.yFID, 0.0f); + } } diff --git a/src/share/native/sun/security/krb5/nativeccache.c b/src/share/native/sun/security/krb5/nativeccache.c index 1b50a2e1761d403ea249828f733a9e31f3a54bec..5ab3f737f24068c344fb7157bbddaafd277ecf55 100644 --- a/src/share/native/sun/security/krb5/nativeccache.c +++ b/src/share/native/sun/security/krb5/nativeccache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, 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 @@ -418,7 +418,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ if (krbcredsConstructor == 0) { krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "", - "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V"); + "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V"); if (krbcredsConstructor == 0) { printf("Couldn't find sun.security.krb5.internal.Ticket constructor\n"); break; @@ -432,7 +432,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ krbcredsConstructor, ticket, clientPrincipal, + NULL, targetPrincipal, + NULL, encryptionKey, ticketFlags, authTime, diff --git a/src/solaris/classes/java/lang/UNIXProcess.java b/src/solaris/classes/java/lang/UNIXProcess.java index 1793a8f35c40499c1609e135f119a46163a12156..fe26fd893014c0fdbfc66e035eaef1d3b77f58e0 100644 --- a/src/solaris/classes/java/lang/UNIXProcess.java +++ b/src/solaris/classes/java/lang/UNIXProcess.java @@ -408,8 +408,7 @@ final class UNIXProcess extends Process { long deadline = System.nanoTime() + remainingNanos; do { - // Round up to next millisecond - wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L)); + TimeUnit.NANOSECONDS.timedWait(this, remainingNanos); if (hasExited) { return true; } diff --git a/src/solaris/native/java/util/TimeZone_md.c b/src/solaris/native/java/util/TimeZone_md.c index 3507c1c6514b8361842b92ac0b64f9b009792880..7ec893b6b62703f0932b430230dbe183259bdcbc 100644 --- a/src/solaris/native/java/util/TimeZone_md.c +++ b/src/solaris/native/java/util/TimeZone_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, 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 @@ -42,6 +42,8 @@ #include "jvm.h" #include "TimeZone_md.h" +static char *isFileIdentical(char* buf, size_t size, char *pathname); + #define SKIP_SPACE(p) while (*p == ' ' || *p == '\t') p++; #if defined(_ALLBSD_SOURCE) @@ -65,6 +67,8 @@ static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo"; static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime"; #endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */ +static const char popularZones[][4] = {"UTC", "GMT"}; + #if defined(_AIX) static const char *ETC_ENVIRONMENT_FILE = "/etc/environment"; #endif @@ -114,14 +118,28 @@ static char * findZoneinfoFile(char *buf, size_t size, const char *dir) { DIR *dirp = NULL; - struct stat statbuf; struct dirent64 *dp = NULL; struct dirent64 *entry = NULL; char *pathname = NULL; - int fd = -1; - char *dbuf = NULL; char *tz = NULL; + if (strcmp(dir, ZONEINFO_DIR) == 0) { + /* fast path for 1st iteration */ + unsigned int i; + for (i = 0; i < sizeof (popularZones) / sizeof (popularZones[0]); i++) { + pathname = getPathName(dir, popularZones[i]); + if (pathname == NULL) { + continue; + } + tz = isFileIdentical(buf, size, pathname); + free((void *) pathname); + pathname = NULL; + if (tz != NULL) { + return tz; + } + } + } + dirp = opendir(dir); if (dirp == NULL) { return NULL; @@ -161,40 +179,14 @@ findZoneinfoFile(char *buf, size_t size, const char *dir) if (pathname == NULL) { break; } - if (stat(pathname, &statbuf) == -1) { - break; - } - if (S_ISDIR(statbuf.st_mode)) { - tz = findZoneinfoFile(buf, size, pathname); - if (tz != NULL) { - break; - } - } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) { - dbuf = (char *) malloc(size); - if (dbuf == NULL) { - break; - } - if ((fd = open(pathname, O_RDONLY)) == -1) { - break; - } - if (read(fd, dbuf, size) != (ssize_t) size) { - break; - } - if (memcmp(buf, dbuf, size) == 0) { - tz = getZoneName(pathname); - if (tz != NULL) { - tz = strdup(tz); - } - break; - } - free((void *) dbuf); - dbuf = NULL; - (void) close(fd); - fd = -1; - } + tz = isFileIdentical(buf, size, pathname); + free((void *) pathname); pathname = NULL; + if (tz != NULL) { + break; + } } if (entry != NULL) { @@ -203,16 +195,53 @@ findZoneinfoFile(char *buf, size_t size, const char *dir) if (dirp != NULL) { (void) closedir(dirp); } - if (pathname != NULL) { - free((void *) pathname); - } - if (fd != -1) { - (void) close(fd); + return tz; +} + +/* + * Checks if the file pointed to by pathname matches + * the data contents in buf. + * Returns a representation of the timezone file name + * if file match is found, otherwise NULL. + */ +static char * +isFileIdentical(char *buf, size_t size, char *pathname) +{ + char *possibleMatch = NULL; + struct stat statbuf; + char *dbuf = NULL; + int fd = -1; + int res; + + if (stat(pathname, &statbuf) == -1) { + return NULL; } - if (dbuf != NULL) { + + if (S_ISDIR(statbuf.st_mode)) { + possibleMatch = findZoneinfoFile(buf, size, pathname); + } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) { + dbuf = (char *) malloc(size); + if (dbuf == NULL) { + return NULL; + } + if ((fd = open(pathname, O_RDONLY)) == -1) { + goto freedata; + } + if (read(fd, dbuf, size) != (ssize_t) size) { + goto freedata; + } + if (memcmp(buf, dbuf, size) == 0) { + possibleMatch = getZoneName(pathname); + if (possibleMatch != NULL) { + possibleMatch = strdup(possibleMatch); + } + } + freedata: free((void *) dbuf); + dbuf = NULL; + (void) close(fd); } - return tz; + return possibleMatch; } #if defined(__linux__) || defined(MACOSX) diff --git a/src/solaris/native/sun/awt/gtk_interface.c b/src/solaris/native/sun/awt/gtk_interface.c index 8157efed4710ece6cffb1aef5fbddddb343554be..42db9b6fe0df228a7e88c4a604e7b511666123f5 100644 --- a/src/solaris/native/sun/awt/gtk_interface.c +++ b/src/solaris/native/sun/awt/gtk_interface.c @@ -44,19 +44,19 @@ typedef struct { } GtkLib; static GtkLib gtk_libs[] = { - { - GTK_2, - JNI_LIB_NAME("gtk-x11-2.0"), - VERSIONED_JNI_LIB_NAME("gtk-x11-2.0", "0"), - >k2_load, - >k2_check - }, { GTK_3, JNI_LIB_NAME("gtk-3"), VERSIONED_JNI_LIB_NAME("gtk-3", "0"), >k3_load, >k3_check + }, + { + GTK_2, + JNI_LIB_NAME("gtk-x11-2.0"), + VERSIONED_JNI_LIB_NAME("gtk-x11-2.0", "0"), + >k2_load, + >k2_check } }; diff --git a/src/solaris/native/sun/java2d/x11/X11SurfaceData.c b/src/solaris/native/sun/java2d/x11/X11SurfaceData.c index b4518af9d9246315fa12ba1ababc79d4d4a3c30e..7d1c058f31bf5432717601547e9a3c320ee088f6 100644 --- a/src/solaris/native/sun/java2d/x11/X11SurfaceData.c +++ b/src/solaris/native/sun/java2d/x11/X11SurfaceData.c @@ -78,6 +78,7 @@ static void X11SD_SwapBytes(X11SDOps *xsdo, XImage *img, int depth, int bpp); static XImage * X11SD_GetImage(JNIEnv *env, X11SDOps *xsdo, SurfaceDataBounds *bounds, jint lockFlags); +static int X11SD_GetBitmapPad(int pixelStride); extern jfieldID validID; @@ -438,11 +439,33 @@ jboolean XShared_initSurface(JNIEnv *env, X11SDOps *xsdo, jint depth, jint width xsdo->drawable = drawable; xsdo->isPixmap = JNI_FALSE; } else { + jboolean sizeIsInvalid = JNI_FALSE; + jlong scan = 0; + /* * width , height must be nonzero otherwise XCreatePixmap * generates BadValue in error_handler */ if (width <= 0 || height <= 0 || width > 32767 || height > 32767) { + sizeIsInvalid = JNI_TRUE; + } else { + XImage* tmpImg = NULL; + + AWT_LOCK(); + tmpImg = XCreateImage(awt_display, + xsdo->configData->awt_visInfo.visual, + depth, ZPixmap, 0, NULL, width, height, + X11SD_GetBitmapPad(xsdo->configData->pixelStride), 0); + if (tmpImg) { + scan = (jlong) tmpImg->bytes_per_line; + XDestroyImage(tmpImg); + tmpImg = NULL; + } + AWT_UNLOCK(); + JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); + } + + if (sizeIsInvalid || (scan * height > 0x7FFFFFFFL)) { JNU_ThrowOutOfMemoryError(env, "Can't create offscreen surface"); return JNI_FALSE; @@ -457,7 +480,7 @@ jboolean XShared_initSurface(JNIEnv *env, X11SDOps *xsdo, jint depth, jint width xsdo->pmHeight = height; #ifdef MITSHM - xsdo->shmPMData.pmSize = width * height * depth; + xsdo->shmPMData.pmSize = (jlong) width * height * depth; xsdo->shmPMData.pixelsReadThreshold = width * height / 8; if (forceSharedPixmaps) { AWT_LOCK(); @@ -560,7 +583,7 @@ XImage* X11SD_CreateSharedImage(X11SDOps *xsdo, return NULL; } shminfo->shmid = - shmget(IPC_PRIVATE, height * img->bytes_per_line, + shmget(IPC_PRIVATE, (size_t) height * img->bytes_per_line, IPC_CREAT|mitShmPermissionMask); if (shminfo->shmid < 0) { J2dRlsTraceLn1(J2D_TRACE_ERROR, @@ -622,7 +645,7 @@ XImage* X11SD_GetSharedImage(X11SDOps *xsdo, jint width, jint height, XSync(awt_display, False); retImage = cachedXImage; cachedXImage = (XImage *)NULL; - } else if (width * height * xsdo->depth > 0x10000) { + } else if ((jlong) width * height * xsdo->depth > 0x10000) { retImage = X11SD_CreateSharedImage(xsdo, width, height); } return retImage; @@ -978,7 +1001,7 @@ static void X11SD_GetRasInfo(JNIEnv *env, int scan = xpriv->img->bytes_per_line; xpriv->x = x; xpriv->y = y; - pRasInfo->rasBase = xpriv->img->data - x * mult - y * scan; + pRasInfo->rasBase = xpriv->img->data - x * mult - (intptr_t) y * scan; pRasInfo->pixelStride = mult; pRasInfo->pixelBitOffset = 0; pRasInfo->scanStride = scan; @@ -1140,8 +1163,8 @@ X11SD_FindClip(SurfaceDataBounds *b, SurfaceDataBounds *bounds, X11SDOps *xsdo) static void X11SD_SwapBytes(X11SDOps *xsdo, XImage * img, int depth, int bpp) { - int lengthInBytes = img->height * img->bytes_per_line; - int i; + jlong lengthInBytes = (jlong) img->height * img->bytes_per_line; + jlong i; switch (depth) { case 12: @@ -1214,7 +1237,7 @@ static XImage * X11SD_GetImage(JNIEnv *env, X11SDOps *xsdo, Drawable drawable; int depth = xsdo->depth; int mult = xsdo->configData->pixelStride; - int pad = (mult == 3) ? 32 : mult * 8; // pad must be 8, 16, or 32 + int pad = X11SD_GetBitmapPad(mult); jboolean readBits = lockFlags & SD_LOCK_NEED_PIXELS; x = bounds->x1; @@ -1280,7 +1303,7 @@ static XImage * X11SD_GetImage(JNIEnv *env, X11SDOps *xsdo, } scan = img->bytes_per_line; - img->data = malloc(h * scan); + img->data = malloc((size_t) h * scan); if (img->data == NULL) { XFree(img); return NULL; @@ -1315,7 +1338,7 @@ static XImage * X11SD_GetImage(JNIEnv *env, X11SDOps *xsdo, int i; img_addr = img->data + - (temp.y1 - y) * scan + (temp.x1 - x) * mult; + (intptr_t) (temp.y1 - y) * scan + (temp.x1 - x) * mult; temp_scan = temp_image->bytes_per_line; temp_addr = temp_image->data; bytes_to_copy = (temp.x2 - temp.x1) * mult; @@ -1349,7 +1372,7 @@ static XImage * X11SD_GetImage(JNIEnv *env, X11SDOps *xsdo, return NULL; } - img->data = malloc(h * img->bytes_per_line); + img->data = malloc((size_t) h * img->bytes_per_line); if (img->data == NULL) { XFree(img); return NULL; @@ -1532,6 +1555,11 @@ X11SD_ReleasePixmapWithBg(JNIEnv *env, X11SDOps *xsdo) #endif /* MITSHM */ } +static int X11SD_GetBitmapPad(int pixelStride) { + // pad must be 8, 16, or 32 + return (pixelStride == 3) ? 32 : pixelStride * 8; +} + #endif /* !HEADLESS */ /* diff --git a/src/solaris/native/sun/java2d/x11/X11SurfaceData.h b/src/solaris/native/sun/java2d/x11/X11SurfaceData.h index 91ad4626a4c51202d8e2bce625f63ed9ed5b4027..cc8ae6a9936cd0e7ec66c4f716f8e035a90230cc 100644 --- a/src/solaris/native/sun/java2d/x11/X11SurfaceData.h +++ b/src/solaris/native/sun/java2d/x11/X11SurfaceData.h @@ -81,7 +81,7 @@ typedef struct { XShmSegmentInfo *shmSegInfo; /* Shared Memory Segment Info */ jint bytesPerLine; /* needed for ShMem lock */ jboolean xRequestSent; /* true if x request is sent w/o XSync */ - jint pmSize; + jlong pmSize; jboolean usingShmPixmap; Drawable pixmap; diff --git a/src/windows/classes/java/lang/ProcessImpl.java b/src/windows/classes/java/lang/ProcessImpl.java index 37c32375475c2455bda26f536eb396c346720743..1970260e57eac3b3af2953f09a7d465cabc7416f 100644 --- a/src/windows/classes/java/lang/ProcessImpl.java +++ b/src/windows/classes/java/lang/ProcessImpl.java @@ -520,11 +520,15 @@ final class ProcessImpl extends Process { if (timeout <= 0) return false; long remainingNanos = unit.toNanos(timeout); - long deadline = System.nanoTime() + remainingNanos ; + long deadline = System.nanoTime() + remainingNanos; do { // Round up to next millisecond long msTimeout = TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L); + if (msTimeout < 0) { + // if wraps around then wait a long while + msTimeout = Integer.MAX_VALUE; + } waitForTimeoutInterruptibly(handle, msTimeout); if (Thread.interrupted()) throw new InterruptedException(); @@ -538,7 +542,7 @@ final class ProcessImpl extends Process { } private static native void waitForTimeoutInterruptibly( - long handle, long timeout); + long handle, long timeoutMillis); public void destroy() { terminateProcess(handle); } diff --git a/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index add8f731ee29b018ff3cab3b71df460780410661..bc4039ad94588bab46240283baaf6e6a773f5ab8 100644 --- a/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -25,7 +25,8 @@ package sun.awt.shell; -import java.awt.*; +import java.awt.Image; +import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.File; @@ -33,14 +34,29 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; -import static sun.awt.shell.Win32ShellFolder2.*; import sun.awt.OSInfo; import sun.misc.ThreadGroupUtils; +import sun.util.logging.PlatformLogger; + +import static sun.awt.shell.Win32ShellFolder2.DESKTOP; +import static sun.awt.shell.Win32ShellFolder2.DRIVES; +import static sun.awt.shell.Win32ShellFolder2.Invoker; +import static sun.awt.shell.Win32ShellFolder2.NETWORK; +import static sun.awt.shell.Win32ShellFolder2.PERSONAL; +import static sun.awt.shell.Win32ShellFolder2.RECENT; // NOTE: This class supersedes Win32ShellFolderManager, which was removed // from distribution after version 1.4.2. @@ -54,6 +70,9 @@ import sun.misc.ThreadGroupUtils; public class Win32ShellFolderManager2 extends ShellFolderManager { + private static final PlatformLogger + log = PlatformLogger.getLogger("sun.awt.shell.Win32ShellFolderManager2"); + static { // Load library here sun.awt.windows.WToolkit.loadLibraries(); @@ -137,12 +156,13 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (desktop == null) { try { desktop = new Win32ShellFolder2(DESKTOP); - } catch (SecurityException e) { - // Ignore error - } catch (IOException e) { - // Ignore error - } catch (InterruptedException e) { - // Ignore error + } catch (final SecurityException ignored) { + // Ignore, the message may have sensitive information, not + // accessible other ways + } catch (IOException | InterruptedException e) { + if (log.isLoggable(PlatformLogger.Level.WARNING)) { + log.warning("Cannot access 'Desktop'", e); + } } } return desktop; @@ -152,12 +172,13 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (drives == null) { try { drives = new Win32ShellFolder2(DRIVES); - } catch (SecurityException e) { - // Ignore error - } catch (IOException e) { - // Ignore error - } catch (InterruptedException e) { - // Ignore error + } catch (final SecurityException ignored) { + // Ignore, the message may have sensitive information, not + // accessible other ways + } catch (IOException | InterruptedException e) { + if (log.isLoggable(PlatformLogger.Level.WARNING)) { + log.warning("Cannot access 'Drives'", e); + } } } return drives; @@ -170,12 +191,13 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (path != null) { recent = createShellFolder(getDesktop(), new File(path)); } - } catch (SecurityException e) { - // Ignore error - } catch (InterruptedException e) { - // Ignore error - } catch (IOException e) { - // Ignore error + } catch (final SecurityException ignored) { + // Ignore, the message may have sensitive information, not + // accessible other ways + } catch (InterruptedException | IOException e) { + if (log.isLoggable(PlatformLogger.Level.WARNING)) { + log.warning("Cannot access 'Recent'", e); + } } } return recent; @@ -185,12 +207,13 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { if (network == null) { try { network = new Win32ShellFolder2(NETWORK); - } catch (SecurityException e) { - // Ignore error - } catch (IOException e) { - // Ignore error - } catch (InterruptedException e) { - // Ignore error + } catch (final SecurityException ignored) { + // Ignore, the message may have sensitive information, not + // accessible other ways + } catch (IOException | InterruptedException e) { + if (log.isLoggable(PlatformLogger.Level.WARNING)) { + log.warning("Cannot access 'Network'", e); + } } } return network; @@ -210,12 +233,13 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { personal.setIsPersonal(); } } - } catch (SecurityException e) { - // Ignore error - } catch (InterruptedException e) { - // Ignore error - } catch (IOException e) { - // Ignore error + } catch (final SecurityException ignored) { + // Ignore, the message may have sensitive information, not + // accessible other ways + } catch (InterruptedException | IOException e) { + if (log.isLoggable(PlatformLogger.Level.WARNING)) { + log.warning("Cannot access 'Personal'", e); + } } } return personal; @@ -316,8 +340,14 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { folders.add(createShellFolder(new File((String)value))); } } catch (IOException e) { + if (log.isLoggable(PlatformLogger.Level.WARNING)) { + log.warning("Cannot read value = " + value, e); + } // Skip this value } catch (InterruptedException e) { + if (log.isLoggable(PlatformLogger.Level.WARNING)) { + log.warning("Cannot read value = " + value, e); + } // Return empty result return new File[0]; } diff --git a/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java b/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java index a436d585cba1939d6fff03d4b4ee2c99cff4abdc..5839a5e13e4a72488b3f0abe482736b8a7e84ec7 100644 --- a/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java +++ b/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java @@ -36,7 +36,6 @@ import sun.security.krb5.internal.*; import sun.security.krb5.internal.ccache.*; import java.io.IOException; import java.util.Arrays; -import javax.security.auth.kerberos.KerberosPrincipal; import sun.security.util.Password; import javax.security.auth.kerberos.KeyTab; @@ -53,22 +52,9 @@ public class Kinit { /** * The main method is used to accept user command line input for ticket - * request. - *

      - * Usage: kinit [-A] [-f] [-p] [-c cachename] [[-k [-t keytab_file_name]] - * [principal] [password] - *

        - *
      • -A do not include addresses - *
      • -f forwardable - *
      • -p proxiable - *
      • -c cache name (i.e., FILE://c:\temp\mykrb5cc) - *
      • -k use keytab - *
      • -t keytab file name - *
      • principal the principal name (i.e., duke@java.sun.com) - *
      • password the principal's Kerberos password - *
      - *

      - * Use java sun.security.krb5.tools.Kinit -help to bring up help menu. + * request. Read {@link KinitOptions#printHelp} for usages or call + * java sun.security.krb5.internal.tools.Kinit -help + * to bring up help menu. *

      * We currently support only file-based credentials cache to * store the tickets obtained from the KDC. @@ -146,6 +132,49 @@ public class Kinit { } else { options = new KinitOptions(args); } + switch (options.action) { + case 1: + acquire(); + break; + case 2: + renew(); + break; + default: + throw new KrbException("kinit does not support action " + + options.action); + } + } + + private void renew() + throws IOException, RealmException, KrbException { + + PrincipalName principal = options.getPrincipal(); + String realm = principal.getRealmAsString(); + CredentialsCache cache = CredentialsCache.getInstance(options.cachename); + + if (cache == null) { + throw new IOException("Unable to find existing cache file " + + options.cachename); + } + sun.security.krb5.internal.ccache.Credentials credentials = + cache.getCreds(PrincipalName.tgsService(realm, realm)); + + credentials = credentials.setKrbCreds() + .renew() + .toCCacheCreds(); + + cache = CredentialsCache.create(principal, options.cachename); + if (cache == null) { + throw new IOException("Unable to create the cache file " + + options.cachename); + } + cache.update(credentials); + cache.save(); + } + + private void acquire() + throws IOException, RealmException, KrbException { + String princName = null; PrincipalName principal = options.getPrincipal(); if (principal != null) { @@ -216,6 +245,9 @@ public class Kinit { if (options.getAddressOption()) builder.setAddresses(HostAddresses.getLocalAddresses()); + builder.setTill(options.lifetime); + builder.setRTime(options.renewable_lifetime); + builder.action(); sun.security.krb5.internal.ccache.Credentials credentials = diff --git a/src/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java b/src/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java index e7507a0a27fd31695f1a04b4656f80ccb31a545e..23bfecad83748c617db441d6d9d9d7f040ae733d 100644 --- a/src/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java +++ b/src/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java @@ -33,12 +33,8 @@ package sun.security.krb5.internal.tools; import sun.security.krb5.*; import sun.security.krb5.internal.*; import sun.security.krb5.internal.ccache.*; -import java.io.File; import java.io.IOException; -import java.util.StringTokenizer; -import java.util.Vector; -import java.io.BufferedReader; -import java.io.InputStreamReader; +import java.time.Instant; import java.io.FileInputStream; /** @@ -49,14 +45,15 @@ import java.io.FileInputStream; * @author Ram Marti */ class KinitOptions { - public boolean validate = false; + + // 1. acquire, 2. renew, 3. validate + public int action = 1; // forwardable and proxiable flags have two states: // -1 - flag set to be not forwardable or proxiable; // 1 - flag set to be forwardable or proxiable. - public short forwardable = -1; - public short proxiable = -1; - public boolean renew = false; + public short forwardable = 0; + public short proxiable = 0; public KerberosTime lifetime; public KerberosTime renewable_lifetime; public String target_service; @@ -134,6 +131,12 @@ class KinitOptions { } useKeytab = true; + } else if (args[i].equals("-R")) { + action = 2; + } else if (args[i].equals("-l")) { + lifetime = getTime(Config.duration(args[++i])); + } else if (args[i].equals("-r")) { + renewable_lifetime = getTime(Config.duration(args[++i])); } else if (args[i].equalsIgnoreCase("-help")) { printHelp(); System.exit(0); @@ -223,23 +226,28 @@ class KinitOptions { void printHelp() { - System.out.println("Usage: kinit " + - "[-A] [-f] [-p] [-c cachename] " + - "[[-k [-t keytab_file_name]] [principal] " + + System.out.println("Usage:\n\n1. Initial ticket request:\n" + + " kinit [-A] [-f] [-p] [-c cachename] " + + "[-l lifetime] [-r renewable_time]\n" + + " [[-k [-t keytab_file_name]] [principal] " + "[password]"); - System.out.println("\tavailable options to " + + System.out.println("2. Renew a ticket:\n" + + " kinit -R [-c cachename] [principal]"); + System.out.println("\nAvailable options to " + "Kerberos 5 ticket request:"); - System.out.println("\t -A do not include addresses"); - System.out.println("\t -f forwardable"); - System.out.println("\t -p proxiable"); - System.out.println("\t -c cache name " + - "(i.e., FILE:\\d:\\myProfiles\\mykrb5cache)"); - System.out.println("\t -k use keytab"); - System.out.println("\t -t keytab file name"); - System.out.println("\t principal the principal name "+ - "(i.e., qweadf@ATHENA.MIT.EDU qweadf)"); - System.out.println("\t password " + - "the principal's Kerberos password"); + System.out.println("\t-A do not include addresses"); + System.out.println("\t-f forwardable"); + System.out.println("\t-p proxiable"); + System.out.println("\t-c cache name " + + "(i.e., FILE:\\d:\\myProfiles\\mykrb5cache)"); + System.out.println("\t-l lifetime"); + System.out.println("\t-r renewable time " + + "(total lifetime a ticket can be renewed)"); + System.out.println("\t-k use keytab"); + System.out.println("\t-t keytab file name"); + System.out.println("\tprincipal the principal name "+ + "(i.e., qweadf@ATHENA.MIT.EDU qweadf)"); + System.out.println("\tpassword the principal's Kerberos password"); } public boolean getAddressOption() { @@ -257,4 +265,8 @@ class KinitOptions { public PrincipalName getPrincipal() { return principal; } + + private KerberosTime getTime(int s) { + return new KerberosTime(Instant.now().plusSeconds(s)); + } } diff --git a/src/windows/native/java/lang/ProcessImpl_md.c b/src/windows/native/java/lang/ProcessImpl_md.c index 3a013c1591c081f5cabaaf275061213bb1b93786..8dcf8972e1e476aae2c4e92a9a0a08ac9e1480a2 100644 --- a/src/windows/native/java/lang/ProcessImpl_md.c +++ b/src/windows/native/java/lang/ProcessImpl_md.c @@ -421,10 +421,10 @@ JNIEXPORT void JNICALL Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env, jclass ignored, jlong handle, - jlong timeout) + jlong timeoutMillis) { HANDLE events[2]; - DWORD dwTimeout = (DWORD)timeout; + DWORD dwTimeout = (DWORD)timeoutMillis; DWORD result; events[0] = (HANDLE) handle; events[1] = JVM_GetThreadInterruptEvent(); diff --git a/src/windows/native/sun/security/krb5/NativeCreds.c b/src/windows/native/sun/security/krb5/NativeCreds.c index b7f81d2f0d035c331e3895b51c492e9c2d820012..ec891a929a1e6fdc14feed527c392196c393fc44 100644 --- a/src/windows/native/sun/security/krb5/NativeCreds.c +++ b/src/windows/native/sun/security/krb5/NativeCreds.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -404,6 +404,8 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ "(Lsun/security/krb5/internal/Ticket;" "Lsun/security/krb5/PrincipalName;" "Lsun/security/krb5/PrincipalName;" + "Lsun/security/krb5/PrincipalName;" + "Lsun/security/krb5/PrincipalName;" "Lsun/security/krb5/EncryptionKey;" "Lsun/security/krb5/internal/TicketFlags;" "Lsun/security/krb5/internal/KerberosTime;" @@ -665,7 +667,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ krbcredsConstructor, ticket, clientPrincipal, + NULL, targetPrincipal, + NULL, encryptionKey, ticketFlags, authTime, // mdu diff --git a/test/ProblemList.txt b/test/ProblemList.txt index b94b2926ef190489375b236107549d119eb5a5c9..c86b5ec52ffb180944dd52bf65516bab47880d06 100644 --- a/test/ProblemList.txt +++ b/test/ProblemList.txt @@ -270,6 +270,9 @@ sun/rmi/transport/tcp/DisableRMIOverHttp/DisableRMIOverHTTPTest.java windows- # 8026976 sun/security/pkcs11/ec/TestKeyFactory.java generic-all +# 8180837 +sun/security/pkcs11/Secmod/AddTrustedCert.java generic-all +sun/security/pkcs11/tls/TestKeyMaterial.java generic-all # 7164518 sun/security/krb5/auto/Unreachable.java macosx-all diff --git a/test/com/sun/tools/attach/StartManagementAgent.java b/test/com/sun/tools/attach/StartManagementAgent.java index da8289558ae05b11c7651c93aeb458f8a3fe807b..cc3969084ebb37131fb844931c0aa8b765dd7231 100644 --- a/test/com/sun/tools/attach/StartManagementAgent.java +++ b/test/com/sun/tools/attach/StartManagementAgent.java @@ -93,7 +93,7 @@ public class StartManagementAgent { } catch(AttachOperationFailedException ex) { // We expect parsing of "apa" above to fail, but if the file path // can't be read we get a different exception message - if (!ex.getMessage().contains("Invalid com.sun.management.jmxremote.port number")) { + if (!ex.getMessage().contains("NumberFormatException: For input string: \"apa\"")) { throw ex; } } diff --git a/test/java/awt/GraphicsDevice/CheckDisplayModes.java b/test/java/awt/GraphicsDevice/CheckDisplayModes.java index 719ee9b43a7d785aed465cdba7f7976b99942ea5..9fced188d63c4c745c39ed1b70d6a60a32af0866 100644 --- a/test/java/awt/GraphicsDevice/CheckDisplayModes.java +++ b/test/java/awt/GraphicsDevice/CheckDisplayModes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8007146 + * @bug 8007146 8213119 * @summary [macosx] Setting a display mode crashes JDK under VNC * @author Alexander Scherbatiy * @run main CheckDisplayModes @@ -36,27 +36,28 @@ public class CheckDisplayModes { public static void main(String[] args) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice graphicDevice = ge.getDefaultScreenDevice(); - if (!graphicDevice.isDisplayChangeSupported()) { - System.err.println("Display mode change is not supported on this host. Test is considered passed."); - return; - } - DisplayMode defaultDisplayMode = graphicDevice.getDisplayMode(); - checkDisplayMode(defaultDisplayMode); - graphicDevice.setDisplayMode(defaultDisplayMode); + for (GraphicsDevice graphicDevice : ge.getScreenDevices()) { + if (!graphicDevice.isDisplayChangeSupported()) { + System.err.println("Display mode change is not supported on this host. Test is considered passed."); + continue; + } + DisplayMode defaultDisplayMode = graphicDevice.getDisplayMode(); + checkDisplayMode(defaultDisplayMode); + graphicDevice.setDisplayMode(defaultDisplayMode); - DisplayMode[] displayModes = graphicDevice.getDisplayModes(); - boolean isDefaultDisplayModeIncluded = false; - for (DisplayMode displayMode : displayModes) { - checkDisplayMode(displayMode); - graphicDevice.setDisplayMode(displayMode); - if (defaultDisplayMode.equals(displayMode)) { - isDefaultDisplayModeIncluded = true; + DisplayMode[] displayModes = graphicDevice.getDisplayModes(); + boolean isDefaultDisplayModeIncluded = false; + for (DisplayMode displayMode : displayModes) { + checkDisplayMode(displayMode); + graphicDevice.setDisplayMode(displayMode); + if (defaultDisplayMode.equals(displayMode)) { + isDefaultDisplayModeIncluded = true; + } } - } - if (!isDefaultDisplayModeIncluded) { - throw new RuntimeException("Default display mode is not included"); + if (!isDefaultDisplayModeIncluded) { + throw new RuntimeException("Default display mode is not included"); + } } } diff --git a/test/java/io/Serializable/serialFilter/GlobalFilterTest.java b/test/java/io/Serializable/serialFilter/GlobalFilterTest.java index 20503d19ea16a3265047e8c062883f73c865cf17..3810f38d878fde660a51b8cb3162fb7a6ec17aff 100644 --- a/test/java/io/Serializable/serialFilter/GlobalFilterTest.java +++ b/test/java/io/Serializable/serialFilter/GlobalFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -42,9 +42,11 @@ import org.testng.annotations.DataProvider; import sun.misc.ObjectInputFilter; /* @test + * @bug 8231422 * @build GlobalFilterTest SerialFilterTest * @run testng/othervm GlobalFilterTest - * @run testng/othervm -Djdk.serialFilter=java.** GlobalFilterTest + * @run testng/othervm -Djdk.serialFilter=java.** + * -Dexpected-jdk.serialFilter=java.** GlobalFilterTest * @run testng/othervm/policy=security.policy GlobalFilterTest * @run testng/othervm/policy=security.policy * -Djava.security.properties=${test.src}/java.security-extra1 @@ -54,6 +56,10 @@ import sun.misc.ObjectInputFilter; */ @Test public class GlobalFilterTest { + private static final String serialPropName = "jdk.serialFilter"; + private static final String badSerialFilter = "java.lang.StringBuffer;!*"; + private static final String origSerialFilterProperty = + System.setProperty(serialPropName, badSerialFilter); /** * DataProvider of patterns and objects derived from the configured process-wide filter. @@ -62,8 +68,8 @@ public class GlobalFilterTest { @DataProvider(name="globalPatternElements") Object[][] globalPatternElements() { String globalFilter = - System.getProperty("jdk.serialFilter", - Security.getProperty("jdk.serialFilter")); + System.getProperty("expected-" + serialPropName, + Security.getProperty(serialPropName)); if (globalFilter == null) { return new Object[0][]; } @@ -100,12 +106,20 @@ public class GlobalFilterTest { */ @Test() static void globalFilter() { - String pattern = - System.getProperty("jdk.serialFilter", - Security.getProperty("jdk.serialFilter")); ObjectInputFilter filter = ObjectInputFilter.Config.getSerialFilter(); + + // Check that the System.setProperty(jdk.serialFilter) DOES NOT affect the filter. + String asSetSystemProp = System.getProperty(serialPropName, + Security.getProperty(serialPropName)); + Assert.assertNotEquals(Objects.toString(filter, null), asSetSystemProp, + "System.setProperty(\"jdk.serialfilter\", ...) should not change filter: " + + asSetSystemProp); + + String pattern = + System.getProperty("expected-" + serialPropName, + Security.getProperty(serialPropName)); System.out.printf("global pattern: %s, filter: %s%n", pattern, filter); - Assert.assertEquals(pattern, Objects.toString(filter, null), + Assert.assertEquals(Objects.toString(filter, null), pattern, "process-wide filter pattern does not match"); } diff --git a/test/java/io/Serializable/serialFilter/security.policy b/test/java/io/Serializable/serialFilter/security.policy index f986e255e99a7a44ff9fa720876c65d7ecce62d0..a79251b3ecd3a951c9efca6799bda020a59bd22e 100644 --- a/test/java/io/Serializable/serialFilter/security.policy +++ b/test/java/io/Serializable/serialFilter/security.policy @@ -3,7 +3,7 @@ grant { // Specific permission under test permission java.security.SerializablePermission "serialFilter"; // Permissions needed to run the test - permission java.util.PropertyPermission "*", "read"; + permission java.util.PropertyPermission "*", "read,write"; permission java.io.FilePermission "<>", "read,write,delete"; permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; permission java.security.SecurityPermission "*"; diff --git a/test/java/lang/ProcessBuilder/Basic.java b/test/java/lang/ProcessBuilder/Basic.java index 1db1d31d8c4ae76485537bbb18c5e7ba5f5ca15c..7a9260acbf220e805db910a95ef23676423afd58 100644 --- a/test/java/lang/ProcessBuilder/Basic.java +++ b/test/java/lang/ProcessBuilder/Basic.java @@ -61,6 +61,15 @@ public class Basic { /* used for AIX only */ static final String libpath = System.getenv("LIBPATH"); + /** + * Returns the number of milliseconds since time given by + * startNanoTime, which must have been previously returned from a + * call to {@link System.nanoTime()}. + */ + private static long millisElapsedSince(long startNanoTime) { + return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanoTime); + } + private static String commandOutput(Reader r) throws Throwable { StringBuilder sb = new StringBuilder(); int c; @@ -2294,40 +2303,98 @@ public class Basic { //---------------------------------------------------------------- // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS) - // interrupt works as expected. + // interrupt works as expected, if interrupted while waiting. //---------------------------------------------------------------- try { List childArgs = new ArrayList(javaChildArgs); childArgs.add("sleep"); final Process p = new ProcessBuilder(childArgs).start(); final long start = System.nanoTime(); - final CountDownLatch ready = new CountDownLatch(1); - final CountDownLatch done = new CountDownLatch(1); + final CountDownLatch aboutToWaitFor = new CountDownLatch(1); final Thread thread = new Thread() { public void run() { try { - final boolean result; - try { - ready.countDown(); - result = p.waitFor(30000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - return; - } + aboutToWaitFor.countDown(); + Thread.currentThread().interrupt(); + boolean result = p.waitFor(30L * 1000L, TimeUnit.MILLISECONDS); fail("waitFor() wasn't interrupted, its return value was: " + result); - } catch (Throwable t) { - unexpected(t); - } finally { - done.countDown(); - } + } catch (InterruptedException success) { + } catch (Throwable t) { unexpected(t); } + } + }; + + thread.start(); + aboutToWaitFor.await(); + thread.interrupt(); + thread.join(10L * 1000L); + check(millisElapsedSince(start) < 10L * 1000L); + check(!thread.isAlive()); + p.destroy(); + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Check that Process.waitFor(Long.MAX_VALUE, TimeUnit.MILLISECONDS) + // interrupt works as expected, if interrupted while waiting. + //---------------------------------------------------------------- + try { + List childArgs = new ArrayList(javaChildArgs); + childArgs.add("sleep"); + final Process p = new ProcessBuilder(childArgs).start(); + final long start = System.nanoTime(); + final CountDownLatch aboutToWaitFor = new CountDownLatch(1); + + final Thread thread = new Thread() { + public void run() { + try { + aboutToWaitFor.countDown(); + Thread.currentThread().interrupt(); + boolean result = p.waitFor(Long.MAX_VALUE, TimeUnit.MILLISECONDS); + fail("waitFor() wasn't interrupted, its return value was: " + result); + } catch (InterruptedException success) { + } catch (Throwable t) { unexpected(t); } + } + }; + + thread.start(); + aboutToWaitFor.await(); + thread.interrupt(); + thread.join(10L * 1000L); + check(millisElapsedSince(start) < 10L * 1000L); + check(!thread.isAlive()); + p.destroy(); + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS) + // interrupt works as expected, if interrupted before waiting. + //---------------------------------------------------------------- + try { + List childArgs = new ArrayList(javaChildArgs); + childArgs.add("sleep"); + final Process p = new ProcessBuilder(childArgs).start(); + final long start = System.nanoTime(); + final CountDownLatch threadStarted = new CountDownLatch(1); + + final Thread thread = new Thread() { + public void run() { + try { + threadStarted.countDown(); + do { Thread.yield(); } + while (!Thread.currentThread().isInterrupted()); + boolean result = p.waitFor(30L * 1000L, TimeUnit.MILLISECONDS); + fail("waitFor() wasn't interrupted, its return value was: " + result); + } catch (InterruptedException success) { + } catch (Throwable t) { unexpected(t); } } }; thread.start(); - ready.await(); - Thread.sleep(1000); + threadStarted.await(); thread.interrupt(); - done.await(); + thread.join(10L * 1000L); + check(millisElapsedSince(start) < 10L * 1000L); + check(!thread.isAlive()); p.destroy(); } catch (Throwable t) { unexpected(t); } diff --git a/test/java/lang/Runtime/loadLibrary/LoadLibraryTest.java b/test/java/lang/Runtime/loadLibrary/LoadLibraryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..62eac12e186aa3cacfc4f9308c8eedd3b0dcca21 --- /dev/null +++ b/test/java/lang/Runtime/loadLibrary/LoadLibraryTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2018, Amazon and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Azul Systems, Inc. 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 8231584 + * @library /lib/testlibrary + * @run main/othervm LoadLibraryTest + */ + +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.net.MalformedURLException; +import java.net.URLClassLoader; +import java.net.URL; + +public class LoadLibraryTest { + static Thread thread1 = null; + static Thread thread2 = null; + + static volatile boolean thread1Ready = false; + + private static final String TEST_SRC = System.getProperty("test.src"); + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path CLS_DIR = Paths.get("classes"); + + static TestClassLoader loader; + static void someLibLoad() { + try { +/* + FileSystems.getDefault(); + + // jdk/jdk: loads directly from Bootstrap Classloader (doesn't take lock on Runtime) + java.net.NetworkInterface.getNetworkInterfaces(); + + System.out.println(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); +*/ + Class c = Class.forName("Target2", true, loader); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + static class TestClassLoader extends URLClassLoader { + boolean passed = false; + + public boolean passed() { + return passed; + } + + TestClassLoader() throws MalformedURLException { + super(new URL[] { new URL("file://" + CLS_DIR.toAbsolutePath().toString() + '/') }); + } + + public String findLibrary(String name) { + System.out.println("findLibrary " + name); + + if ("someLibrary".equals(name)) { + try { + synchronized(thread1) { + while(!thread1Ready) { + thread1.wait(); + } + thread1.notifyAll(); + } + + Thread.sleep(10000); + + System.out.println("Thread2 load"); + someLibLoad(); + + // no deadlock happened + passed = true; + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + } + + return super.findLibrary(name); + } + } + + + public static void main(String[] args) throws Exception { + loader = new TestClassLoader(); + + if (!CompilerUtils.compile(SRC_DIR, CLS_DIR)) { + throw new Exception("Can't compile"); + } + + thread1 = new Thread() { + public void run() { + try { + synchronized(this) { + thread1Ready = true; + thread1.notifyAll(); + thread1.wait(); + } + } catch(InterruptedException e) { + throw new RuntimeException(e); + } + + System.out.println("Thread1 load"); + someLibLoad(); + }; + }; + + thread2 = new Thread() { + public void run() { + try { + Class c = Class.forName("Target", true, loader); + System.out.println(c); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + }; + + thread1.setDaemon(true); + thread2.setDaemon(true); + + thread1.start(); + thread2.start(); + + thread1.join(); + thread2.join(); + + if (!loader.passed()) { + throw new RuntimeException("FAIL"); + } + } +} diff --git a/test/java/lang/Runtime/loadLibrary/src/Target.java b/test/java/lang/Runtime/loadLibrary/src/Target.java new file mode 100644 index 0000000000000000000000000000000000000000..fc51481053d40deb161c68d4180a1ea7a90308ae --- /dev/null +++ b/test/java/lang/Runtime/loadLibrary/src/Target.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019, Azul Systems, Inc. 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. + */ + +class Target { + static { + try { + System.loadLibrary("someLibrary"); + throw new RuntimeException("someLibrary was loaded"); + } catch (UnsatisfiedLinkError e) { + // expected: we do not have a someLibrary + } + } +} + diff --git a/test/java/lang/Runtime/loadLibrary/src/Target2.java b/test/java/lang/Runtime/loadLibrary/src/Target2.java new file mode 100644 index 0000000000000000000000000000000000000000..bc8dfc5e63beccaa1d5d8b5489adeaf99101a5e3 --- /dev/null +++ b/test/java/lang/Runtime/loadLibrary/src/Target2.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019, Azul Systems, Inc. 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. + */ + +class Target2 { + static { + System.loadLibrary("awt"); + } +} + diff --git a/test/java/lang/annotation/AnnotationType/AnnotationTypeRuntimeAssumptionTest.java b/test/java/lang/annotation/AnnotationType/AnnotationTypeRuntimeAssumptionTest.java index 2d79c61bc3c522e3533531c0e5f9084b49983875..32589256c59e83843aeae6fdba646fb4c31c4034 100644 --- a/test/java/lang/annotation/AnnotationType/AnnotationTypeRuntimeAssumptionTest.java +++ b/test/java/lang/annotation/AnnotationType/AnnotationTypeRuntimeAssumptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -25,15 +25,18 @@ * @test * @summary Test consistent parsing of ex-RUNTIME annotations that * were changed and separately compiled to have CLASS retention + * @library /lib/testlibrary + * @build jdk.testlibrary.IOUtils + * @run main AnnotationTypeRuntimeAssumptionTest */ -import sun.misc.IOUtils; - import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import jdk.testlibrary.IOUtils; + import static java.lang.annotation.RetentionPolicy.CLASS; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -137,7 +140,7 @@ public class AnnotationTypeRuntimeAssumptionTest { String altPath = altName.replace('.', '/').concat(".class"); try (InputStream is = getResourceAsStream(altPath)) { if (is != null) { - byte[] bytes = IOUtils.readFully(is, -1, true); + byte[] bytes = IOUtils.readFully(is); // patch class bytes to contain original name for (int i = 0; i < bytes.length - 2; i++) { if (bytes[i] == '_' && @@ -160,7 +163,7 @@ public class AnnotationTypeRuntimeAssumptionTest { String path = name.replace('.', '/').concat(".class"); try (InputStream is = getResourceAsStream(path)) { if (is != null) { - byte[] bytes = IOUtils.readFully(is, -1, true); + byte[] bytes = IOUtils.readFully(is); return defineClass(name, bytes, 0, bytes.length); } else { diff --git a/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java b/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java index 9d38102b14afda77b413c051f486e52765a4ddd2..6c97e3407cb85e4bc0731c311d398bb4c6a587be 100644 --- a/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java +++ b/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -22,11 +22,14 @@ */ /* -@test -@bug 8004970 -@summary Lambda serialization in the presence of class loaders -@author Peter Levart -*/ + * @test + * @bug 8004970 + * @summary Lambda serialization in the presence of class loaders + * @library /lib/testlibrary + * @build jdk.testlibrary.IOUtils + * @run main LambdaClassLoaderSerialization + * @author Peter Levart + */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -37,6 +40,8 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays; +import jdk.testlibrary.IOUtils; + public class LambdaClassLoaderSerialization { public interface SerializableRunnable extends Runnable, Serializable {} @@ -125,7 +130,7 @@ public class LambdaClassLoaderSerialization { String path = name.replace('.', '/').concat(".class"); try (InputStream is = getResourceAsStream(path)) { if (is != null) { - byte[] bytes = readFully(is); + byte[] bytes = IOUtils.readFully(is); return defineClass(name, bytes, 0, bytes.length); } else { throw new ClassNotFoundException(name); @@ -135,30 +140,5 @@ public class LambdaClassLoaderSerialization { throw new ClassNotFoundException(name, e); } } - - static byte[] readFully(InputStream is) throws IOException { - byte[] output = {}; - int pos = 0; - while (true) { - int bytesToRead; - if (pos >= output.length) { // Only expand when there's no room - bytesToRead = output.length + 1024; - if (output.length < pos + bytesToRead) { - output = Arrays.copyOf(output, pos + bytesToRead); - } - } else { - bytesToRead = output.length - pos; - } - int cc = is.read(output, pos, bytesToRead); - if (cc < 0) { - if (output.length != pos) { - output = Arrays.copyOf(output, pos); - } - break; - } - pos += cc; - } - return output; - } } } diff --git a/test/java/lang/reflect/Method/InterfaceStatic/StaticInterfaceMethodInWayOfDefault.java b/test/java/lang/reflect/Method/InterfaceStatic/StaticInterfaceMethodInWayOfDefault.java index ffb384f20a7356c8e3814666c01c7fb283a2937d..4ad93eb344717e21c6711a3105089be8ebbf2249 100644 --- a/test/java/lang/reflect/Method/InterfaceStatic/StaticInterfaceMethodInWayOfDefault.java +++ b/test/java/lang/reflect/Method/InterfaceStatic/StaticInterfaceMethodInWayOfDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -27,6 +27,9 @@ * @summary Test that a static method on an interface doesn't hide a default * method with the same name and signature in a separate compilation * scenario. + * @library /lib/testlibrary + * @build jdk.testlibrary.IOUtils + * @run main StaticInterfaceMethodInWayOfDefault */ import java.io.IOException; @@ -35,7 +38,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.concurrent.Callable; -import sun.misc.IOUtils; +import jdk.testlibrary.IOUtils; public class StaticInterfaceMethodInWayOfDefault { public interface A_v1 { @@ -144,7 +147,7 @@ public class StaticInterfaceMethodInWayOfDefault { String altPath = altName.replace('.', '/').concat(".class"); try (InputStream is = getResourceAsStream(altPath)) { if (is != null) { - byte[] bytes = IOUtils.readFully(is, -1, true); + byte[] bytes = IOUtils.readFully(is); // patch class bytes to contain original name for (int i = 0; i < bytes.length - 2; i++) { if (bytes[i] == '_' && @@ -167,7 +170,7 @@ public class StaticInterfaceMethodInWayOfDefault { String path = name.replace('.', '/').concat(".class"); try (InputStream is = getResourceAsStream(path)) { if (is != null) { - byte[] bytes = IOUtils.readFully(is, -1, true); + byte[] bytes = IOUtils.readFully(is); return defineClass(name, bytes, 0, bytes.length); } else { diff --git a/test/java/security/testlibrary/Proc.java b/test/java/security/testlibrary/Proc.java index 1ab58bf52125eaf4f74076d348df7923e4e9b39d..95192cd136958fc64945a0d182293e0354a50cc9 100644 --- a/test/java/security/testlibrary/Proc.java +++ b/test/java/security/testlibrary/Proc.java @@ -235,6 +235,13 @@ public class Proc { br = new BufferedReader(new InputStreamReader(p.getInputStream())); return this; } + String getId(String suffix) { + if (debug != null) { + return debug + "." + suffix; + } else { + return System.identityHashCode(this) + "." + suffix; + } + } // Reads a line from stdout of proc public String readLine() throws IOException { String s = br.readLine(); @@ -303,9 +310,13 @@ public class Proc { boolean isEmpty = true; while (true) { int i = System.in.read(); - if (i == -1) break; + if (i == -1) { + break; + } isEmpty = false; - if (i == '\n') break; + if (i == '\n') { + break; + } if (i != 13) { // Force it to a char, so only simple ASCII works. sb.append((char)i); diff --git a/test/lib/testlibrary/ClassFileInstaller.java b/test/lib/testlibrary/ClassFileInstaller.java index dd8777b1ff21449ef923b3d9d31bad3622a1d053..0f5b515a6c95a92f72fc8cb3631105a3f81fcc6e 100644 --- a/test/lib/testlibrary/ClassFileInstaller.java +++ b/test/lib/testlibrary/ClassFileInstaller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -21,28 +21,229 @@ * questions. */ +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileNotFoundException; import java.io.InputStream; +import java.io.ByteArrayInputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** - * Dump a class file for a class on the class path in the current directory + * Dump a class file for a class on the class path in the current directory, or + * in the specified JAR file. This class is usually used when you build a class + * from a test library, but want to use this class in a sub-process. + * + * For example, to build the following library class: + * test/lib/sun/hotspot/WhiteBox.java + * + * You would use the following tags: + * + * @library /test/lib + * @build sun.hotspot.WhiteBox + * + * JTREG would build the class file under + * ${JTWork}/classes/test/lib/sun/hotspot/WhiteBox.class + * + * With you run your main test class using "@run main MyMainClass", JTREG would setup the + * -classpath to include "${JTWork}/classes/test/lib/", so MyMainClass would be able to + * load the WhiteBox class. + * + * However, if you run a sub process, and do not wish to use the exact same -classpath, + * You can use ClassFileInstaller to ensure that WhiteBox is available in the current + * directory of your test: + * + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * + * Or, you can use the -jar option to store the class in the specified JAR file. If a relative + * path name is given, the JAR file would be relative to the current directory of + * + * @run main ClassFileInstaller -jar myjar.jar sun.hotspot.WhiteBox */ public class ClassFileInstaller { + /** + * You can enable debug tracing of ClassFileInstaller by running JTREG with + * jtreg -DClassFileInstaller.debug=true ... + */ + public static boolean DEBUG = Boolean.getBoolean("ClassFileInstaller.debug"); + /** * @param args The names of the classes to dump * @throws Exception */ public static void main(String... args) throws Exception { - for (String arg : args) { - ClassLoader cl = ClassFileInstaller.class.getClassLoader(); + if (args.length > 1 && args[0].equals("-jar")) { + if (args.length < 2) { + throw new RuntimeException("Usage: ClassFileInstaller \n" + + "where possible options include:\n" + + " -jar Write to the JAR file "); + } + writeJar(args[1], null, args, 2, args.length); + } else { + if (DEBUG) { + System.out.println("ClassFileInstaller: Writing to " + System.getProperty("user.dir")); + } + for (String arg : args) { + writeClassToDisk(arg); + } + } + } + + public static class Manifest { + private InputStream in; + + private Manifest(InputStream in) { + this.in = in; + } + + static Manifest fromSourceFile(String fileName) throws Exception { + String pathName = System.getProperty("test.src") + File.separator + fileName; + return new Manifest(new FileInputStream(pathName)); + } + + // Example: + // String manifest = "Premain-Class: RedefineClassHelper\n" + + // "Can-Redefine-Classes: true\n"; + // ClassFileInstaller.writeJar("redefineagent.jar", + // ClassFileInstaller.Manifest.fromString(manifest), + // "RedefineClassHelper"); + static Manifest fromString(String manifest) throws Exception { + return new Manifest(new ByteArrayInputStream(manifest.getBytes())); + } + + public InputStream getInputStream() { + return in; + } + } + + private static void writeJar(String jarFile, Manifest manifest, String classes[], int from, int to) throws Exception { + if (DEBUG) { + System.out.println("ClassFileInstaller: Writing to " + getJarPath(jarFile)); + } + + (new File(jarFile)).delete(); + FileOutputStream fos = new FileOutputStream(jarFile); + ZipOutputStream zos = new ZipOutputStream(fos); + + // The manifest must be the first or second entry. See comments in JarInputStream + // constructor and JDK-5046178. + if (manifest != null) { + writeToDisk(zos, "META-INF/MANIFEST.MF", manifest.getInputStream()); + } + + for (int i=from; i 0) { + pathName = prependPath + "/" + pathName; + } + writeToDisk(zos, pathName, is); + } + + public static void writeClassToDisk(String className, byte[] bytecode) throws Exception { + writeClassToDisk(null, className, bytecode); + } + private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode) throws Exception { + writeClassToDisk(zos, className, bytecode, ""); + } + + public static void writeClassToDisk(String className, byte[] bytecode, String prependPath) throws Exception { + writeClassToDisk(null, className, bytecode, prependPath); + } + private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode, String prependPath) throws Exception { + // Convert dotted class name to a path to a class file + String pathName = className.replace('.', '/').concat(".class"); + if (prependPath.length() > 0) { + pathName = prependPath + "/" + pathName; + } + writeToDisk(zos, pathName, new ByteArrayInputStream(bytecode)); + } + + private static void writeToDisk(ZipOutputStream zos, String pathName, InputStream is) throws Exception { + if (DEBUG) { + System.out.println("ClassFileInstaller: Writing " + pathName); + } + if (zos != null) { + ZipEntry ze = new ZipEntry(pathName); + zos.putNextEntry(ze); + byte[] buf = new byte[1024]; + int len; + while ((len = is.read(buf))>0){ + zos.write(buf, 0, len); + } + } else { // Create the class file's package directory Path p = Paths.get(pathName); Path parent = p.getParent(); @@ -52,5 +253,6 @@ public class ClassFileInstaller { // Create the class file Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); } + is.close(); } } diff --git a/test/lib/testlibrary/jdk/testlibrary/FileUtils.java b/test/lib/testlibrary/jdk/testlibrary/FileUtils.java index b9f3088040169dfd600a2571420c2e958f79d754..587bf82aeb53e98c9faf148100ee6ebf912f9508 100644 --- a/test/lib/testlibrary/jdk/testlibrary/FileUtils.java +++ b/test/lib/testlibrary/jdk/testlibrary/FileUtils.java @@ -228,4 +228,3 @@ public final class FileUtils { return areFileSystemsAccessible; } } - diff --git a/test/lib/testlibrary/jdk/testlibrary/IOUtils.java b/test/lib/testlibrary/jdk/testlibrary/IOUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..4bfddd0485c6fddb0c9e2369662c4d230e15e197 --- /dev/null +++ b/test/lib/testlibrary/jdk/testlibrary/IOUtils.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014, 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. + */ + +package jdk.testlibrary; + +/** + * Defines useful I/O methods. + */ +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +public final class IOUtils { + + /* + * Prevent instantiation. + */ + private IOUtils() {} + + /** + * Read all bytes from in + * until EOF is detected. + * @param in input stream, must not be null + * @return bytes read + * @throws IOException Any IO error. + */ + public static byte[] readFully(InputStream is) throws IOException { + byte[] output = {}; + int pos = 0; + while (true) { + int bytesToRead; + if (pos >= output.length) { // Only expand when there's no room + bytesToRead = output.length + 1024; + if (output.length < pos + bytesToRead) { + output = Arrays.copyOf(output, pos + bytesToRead); + } + } else { + bytesToRead = output.length - pos; + } + int cc = is.read(output, pos, bytesToRead); + if (cc < 0) { + if (output.length != pos) { + output = Arrays.copyOf(output, pos); + } + break; + } + pos += cc; + } + return output; + } +} diff --git a/test/sun/misc/IOUtils/ReadAllBytes.java b/test/sun/misc/IOUtils/ReadAllBytes.java new file mode 100644 index 0000000000000000000000000000000000000000..440aad09a34ee8193f198c48934ac395d5aaabc5 --- /dev/null +++ b/test/sun/misc/IOUtils/ReadAllBytes.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Random; + +import jdk.testlibrary.RandomFactory; + +import sun.misc.IOUtils; + +/* + * @test + * @bug 8080835 8193832 + * @library /lib/testlibrary + * @build jdk.testlibrary.* + * @run main ReadAllBytes + * @summary Basic test for IOUtils.readAllBytes + * @key randomness + */ + +public class ReadAllBytes { + + private static Random generator = RandomFactory.getRandom(); + + public static void main(String[] args) throws IOException { + test(new byte[]{}); + test(new byte[]{1, 2, 3}); + test(createRandomBytes(1024)); + for (int shift : new int[] {13, 14, 15, 17}) { + for (int offset : new int[] {-1, 0, 1}) { + test(createRandomBytes((1 << shift) + offset)); + } + } + } + + static void test(byte[] expectedBytes) throws IOException { + int expectedLength = expectedBytes.length; + WrapperInputStream in = new WrapperInputStream(new ByteArrayInputStream(expectedBytes)); + byte[] readBytes = IOUtils.readAllBytes(in); + + int x; + byte[] tmp = new byte[10]; + check((x = in.read()) == -1, + "Expected end of stream from read(), got " + x); + check((x = in.read(tmp)) == -1, + "Expected end of stream from read(byte[]), got " + x); + check((x = in.read(tmp, 0, tmp.length)) == -1, + "Expected end of stream from read(byte[], int, int), got " + x); + check(IOUtils.readAllBytes(in).length == 0, + "Expected readAllBytes to return empty byte array"); + check(expectedLength == readBytes.length, + "Expected length " + expectedLength + ", got " + readBytes.length); + check(Arrays.equals(expectedBytes, readBytes), + "Expected[" + expectedBytes + "], got:[" + readBytes + "]"); + check(!in.isClosed(), "Stream unexpectedly closed"); + } + + static byte[] createRandomBytes(int size) { + byte[] bytes = new byte[size]; + generator.nextBytes(bytes); + return bytes; + } + + static void check(boolean cond, Object ... failedArgs) { + if (cond) + return; + StringBuilder sb = new StringBuilder(); + for (Object o : failedArgs) + sb.append(o); + throw new RuntimeException(sb.toString()); + } + + static class WrapperInputStream extends FilterInputStream { + private boolean closed; + WrapperInputStream(InputStream in) { super(in); } + @Override public void close() throws IOException { closed = true; in.close(); } + boolean isClosed() { return closed; } + } +} diff --git a/test/sun/misc/IOUtils/ReadNBytes.java b/test/sun/misc/IOUtils/ReadNBytes.java new file mode 100644 index 0000000000000000000000000000000000000000..96ae6c367ae524eb3470a37f5800b063f4cdb46a --- /dev/null +++ b/test/sun/misc/IOUtils/ReadNBytes.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015, 2018, 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Random; +import jdk.testlibrary.RandomFactory; + +import sun.misc.IOUtils; + +/* + * @test + * @bug 8080835 8139206 + * @library /lib/testlibrary + * @build jdk.testlibrary.* + * @run main ReadNBytes + * @summary Basic test for IOUtils.readNBytes + * @key randomness + */ + +public class ReadNBytes { + + private static Random generator = RandomFactory.getRandom(); + + public static void main(String[] args) throws IOException { + test(new byte[]{1, 2, 3}); + test(createRandomBytes(1024)); + for (int shift : new int[] {13, 15, 17}) { + for (int offset : new int[] {-1, 0, 1}) { + test(createRandomBytes((1 << shift) + offset)); + } + } + + test(-1); + test(0); + for (int shift : new int[] {13, 15, 17}) { + for (int offset : new int[] {-1, 0, 1}) { + test((1 << shift) + offset); + } + } + } + + static void test(byte[] inputBytes) throws IOException { + int length = inputBytes.length; + WrapperInputStream in = new WrapperInputStream(new ByteArrayInputStream(inputBytes)); + byte[] readBytes = new byte[(length / 2) + 1]; + int nread = IOUtils.readNBytes(in, readBytes, 0, readBytes.length); + + int x; + byte[] tmp; + check(nread == readBytes.length, + "Expected number of bytes read: " + readBytes.length + ", got: " + nread); + check(Arrays.equals((tmp = Arrays.copyOf(inputBytes, nread)), readBytes), + "Expected[" + tmp + "], got:[" + readBytes + "]"); + check(!in.isClosed(), "Stream unexpectedly closed"); + + // Read again + nread = IOUtils.readNBytes(in, readBytes, 0, readBytes.length); + + check(nread == length - readBytes.length, + "Expected number of bytes read: " + (length - readBytes.length) + ", got: " + nread); + check(Arrays.equals((tmp = Arrays.copyOfRange(inputBytes, readBytes.length, length)), + Arrays.copyOf(readBytes, nread)), + "Expected[" + tmp + "], got:[" + readBytes + "]"); + // Expect end of stream + check((x = in.read()) == -1, + "Expected end of stream from read(), got " + x); + check((x = in.read(tmp)) == -1, + "Expected end of stream from read(byte[]), got " + x); + check((x = in.read(tmp, 0, tmp.length)) == -1, + "Expected end of stream from read(byte[], int, int), got " + x); + check((x = IOUtils.readNBytes(in, tmp, 0, tmp.length)) == 0, + "Expected end of stream, 0, from readNBytes(byte[], int, int), got " + x); + check(!in.isClosed(), "Stream unexpectedly closed"); + } + + static void test(int max) throws IOException { + byte[] subset1, subset2; + byte[] inputBytes = max <= 0 ? new byte[0] : createRandomBytes(max); + WrapperInputStream in = + new WrapperInputStream(new ByteArrayInputStream(inputBytes)); + + if (max < 0) { + try { + IOUtils.readNBytes(in, max); + check(false, "Expected IllegalArgumentException not thrown"); + } catch (IllegalArgumentException iae) { + return; + } + } else if (max == 0) { + int x; + check((x = IOUtils.readNBytes(in, max).length) == 0, + "Expected zero bytes, got " + x); + return; + } + + int off = Math.toIntExact(in.skip(generator.nextInt(max/2))); + int len = generator.nextInt(max - 1 - off); + byte[] readBytes = IOUtils.readNBytes(in, len); + check(readBytes.length == len, + "Expected " + len + " bytes, got " + readBytes.length); + subset1 = Arrays.copyOfRange(inputBytes, off, off + len); + subset2 = Arrays.copyOfRange(readBytes, 0, len); + check(Arrays.equals(subset1, subset2), "Expected[" + subset1 + + "], got:[" + readBytes + "]"); + + int remaining = max - (off + len); + readBytes = IOUtils.readNBytes(in, remaining); + check(readBytes.length == remaining, + "Expected " + remaining + "bytes, got " + readBytes.length); + subset1 = Arrays.copyOfRange(inputBytes, off + len, max); + subset2 = Arrays.copyOfRange(readBytes, 0, remaining); + check(Arrays.equals(subset1, subset2), "Expected[" + subset1 + + "], got:[" + readBytes + "]"); + + check(!in.isClosed(), "Stream unexpectedly closed"); + } + + static byte[] createRandomBytes(int size) { + byte[] bytes = new byte[size]; + generator.nextBytes(bytes); + return bytes; + } + + static void check(boolean cond, Object ... failedArgs) { + if (cond) + return; + StringBuilder sb = new StringBuilder(); + for (Object o : failedArgs) + sb.append(o); + throw new RuntimeException(sb.toString()); + } + + + static class WrapperInputStream extends FilterInputStream { + private boolean closed; + WrapperInputStream(InputStream in) { super(in); } + @Override public void close() throws IOException { closed = true; in.close(); } + boolean isClosed() { return closed; } + } +} diff --git a/test/sun/misc/URLClassPath/JarClassPathFileEntry.java b/test/sun/misc/URLClassPath/JarClassPathFileEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..6f57ec514d6def168ebb9e136f3900fb4e127f51 --- /dev/null +++ b/test/sun/misc/URLClassPath/JarClassPathFileEntry.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019, 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. + */ + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import jdk.testlibrary.InMemoryJavaCompiler; +import jdk.testlibrary.JarUtils; + +/* + * @test + * @bug 8216401 + * @summary Test loading of JAR Class-Path entry with file: scheme + * @library /lib/testlibrary + * + * @run main/othervm JarClassPathFileEntry + * @run main/othervm -Djdk.net.URLClassPath.disableClassPathURLCheck=true JarClassPathFileEntry + * @run main/othervm -Djdk.net.URLClassPath.disableClassPathURLCheck=false JarClassPathFileEntry + */ + +public class JarClassPathFileEntry { + private final static boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows"); + + private final static String TEST_CLASSES = System.getProperty("test.classes"); + private final static String OTHER_DIR = TEST_CLASSES + "/OTHER/"; + + private final static Path OTHER_JAR_PATH = Paths.get(OTHER_DIR, "Other.jar"); + private final static Path CONTEXT_JAR_PATH = Paths.get(TEST_CLASSES, "Context.jar"); + + public static void main(String[] args) throws Throwable { + // Create Other.class in OTHER_DIR, off the default classpath + byte klassbuf[] = InMemoryJavaCompiler.compile("Other", + "public class Other {}"); + ClassFileInstaller.writeClassToDisk("Other", klassbuf, OTHER_DIR); + + // Create Other.jar in OTHER_DIR + JarUtils.createJarFile(OTHER_JAR_PATH, + Paths.get(OTHER_DIR), + Paths.get(OTHER_DIR, "Other.class")); + + // Create Context.class + klassbuf = InMemoryJavaCompiler.compile("Context", + "public class Context {}"); + ClassFileInstaller.writeClassToDisk("Context", klassbuf, TEST_CLASSES); + + // Create Context.jar w/ "file:" entry for Other.jar + Manifest mf = new Manifest(); + Attributes attrs = mf.getMainAttributes(); + attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + + String classPathEntry = "file:" + (IS_WINDOWS ? toUnixPath(OTHER_JAR_PATH.toString()) + : OTHER_JAR_PATH.toString()); + attrs.put(Attributes.Name.CLASS_PATH, classPathEntry); + + System.out.println("Creating Context.jar with Class-Path: " + classPathEntry); + JarUtils.createJarFile(CONTEXT_JAR_PATH, mf, + Paths.get(TEST_CLASSES), + Paths.get(TEST_CLASSES, "Context.class")); + + // Use URLClassLoader w/ Context.jar to load Other.class, which will + // load via the Class-Path entry + URL url = CONTEXT_JAR_PATH.toUri().toURL(); + URLClassLoader ucl = new URLClassLoader(new URL[]{ url }, + null); // don't delegate to App CL + Class otherClass = Class.forName("Other", true, ucl); // ClassNotFoundException -> fail + System.out.println("Loaded: " + otherClass); + } + + /* Convert a Windows path to a unix-style path, and remove any drive letter */ + private static String toUnixPath(String orig) { + String retVal = new File(orig).toURI().getPath(); + int colonAt = retVal.indexOf(':'); + + if (colonAt != -1 && colonAt < 3) { + retVal = retVal.substring(colonAt + 1); // Start after the drive letter + } + return retVal; + } +} diff --git a/test/sun/net/www/B8185898.java b/test/sun/net/www/B8185898.java new file mode 100644 index 0000000000000000000000000000000000000000..67f3998e6bd2c218b51091944900af51690d3082 --- /dev/null +++ b/test/sun/net/www/B8185898.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2019, 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 8185898 + * @library /lib/testlibrary + * @run main/othervm B8185898 + * @summary setRequestProperty(key, null) results in HTTP header without colon in request + */ + +import java.io.*; +import java.net.*; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import java.util.Collections; + +import jdk.testlibrary.net.URIBuilder; +import sun.net.www.MessageHeader; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; + +import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static java.nio.charset.StandardCharsets.UTF_8; + +/* + * Test checks that MessageHeader with key != null and value == null is set correctly + * and printed according to HTTP standard in the format : + * */ +public class B8185898 { + + static HttpServer server; + static final String RESPONSE_BODY = "Test response body"; + static final String H1 = "X-header1"; + static final String H2 = "X-header2"; + static final String VALUE = "This test value should appear"; + static final List oneList = Arrays.asList(VALUE); + static final List zeroList = Arrays.asList(""); + static int port; + static URL url; + static volatile Map> headers; + + static class Handler implements HttpHandler { + + public void handle(HttpExchange t) throws IOException { + InputStream is = t.getRequestBody(); + InetSocketAddress rem = t.getRemoteAddress(); + headers = t.getRequestHeaders(); // Get request headers on the server side + while(is.read() != -1){} + is.close(); + + OutputStream os = t.getResponseBody(); + t.sendResponseHeaders(200, RESPONSE_BODY.length()); + os.write(RESPONSE_BODY.getBytes(UTF_8)); + t.close(); + } + } + + public static void main(String[] args) throws Exception { + ExecutorService exec = Executors.newCachedThreadPool(); + InetAddress loopback = InetAddress.getLoopbackAddress(); + + try { + InetSocketAddress addr = new InetSocketAddress(loopback, 0); + server = HttpServer.create(addr, 100); + HttpHandler handler = new Handler(); + HttpContext context = server.createContext("/", handler); + server.setExecutor(exec); + server.start(); + + port = server.getAddress().getPort(); + System.out.println("Server on port: " + port); + url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(port) + .path("/foo") + .toURLUnchecked(); + System.out.println("URL: " + url); + testMessageHeader(); + testMessageHeaderMethods(); + testURLConnectionMethods(); + } finally { + server.stop(0); + System.out.println("After server shutdown"); + exec.shutdown(); + } + } + + // Test message header with malformed message header and fake request line + static void testMessageHeader() { + final String badHeader = "This is not a request line for HTTP/1.1"; + final String fakeRequestLine = "This /is/a/fake/status/line HTTP/2.0"; + final String expectedHeaders = fakeRequestLine + "\r\n" + + H1 + ": " + VALUE + "\r\n" + + H2 + ": " + VALUE + "\r\n" + + badHeader + ":\r\n\r\n"; + + MessageHeader header = new MessageHeader(); + header.add(H1, VALUE); + header.add(H2, VALUE); + header.add(badHeader, null); + header.prepend(fakeRequestLine, null); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + header.print(new PrintStream(out)); + + if (!out.toString().equals(expectedHeaders)) { + throw new AssertionError("FAILED: expected: " + + expectedHeaders + "\nReceived: " + out.toString()); + } else { + System.out.println("PASSED: ::print returned correct " + + "status line and headers:\n" + out.toString()); + } + } + + // Test MessageHeader::print, ::toString, implicitly testing that + // MessageHeader::mergeHeader formats headers correctly for responses + static void testMessageHeaderMethods() throws IOException { + // {{inputString1, expectedToString1, expectedPrint1}, {...}} + String[][] strings = { + {"HTTP/1.1 200 OK\r\n" + + "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + + "Connection: keep-alive\r\n" + + "Host: 127.0.0.1:12345\r\n" + + "User-agent: Java/12\r\n\r\nfoooo", + "pairs: {null: HTTP/1.1 200 OK}" + + "{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}" + + "{Connection: keep-alive}" + + "{Host: 127.0.0.1:12345}" + + "{User-agent: Java/12}", + "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + + "Connection: keep-alive\r\n" + + "Host: 127.0.0.1:12345\r\n" + + "User-agent: Java/12\r\n\r\n"}, + {"HTTP/1.1 200 OK\r\n" + + "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + + "Connection: keep-alive\r\n" + + "Host: 127.0.0.1:12345\r\n" + + "User-agent: Java/12\r\n" + + "X-Header:\r\n\r\n", + "pairs: {null: HTTP/1.1 200 OK}" + + "{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}" + + "{Connection: keep-alive}" + + "{Host: 127.0.0.1:12345}" + + "{User-agent: Java/12}" + + "{X-Header: }", + "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + + "Connection: keep-alive\r\n" + + "Host: 127.0.0.1:12345\r\n" + + "User-agent: Java/12\r\n" + + "X-Header: \r\n\r\n"}, + }; + + System.out.println("Test custom message headers"); + for (String[] s : strings) { + // Test MessageHeader::toString + MessageHeader header = new MessageHeader( + new ByteArrayInputStream(s[0].getBytes(ISO_8859_1))); + if (!header.toString().endsWith(s[1])) { + throw new AssertionError("FAILED: expected: " + + s[1] + "\nReceived: " + header); + } else { + System.out.println("PASSED: ::toString returned correct " + + "status line and headers:\n" + header); + } + + // Test MessageHeader::print + ByteArrayOutputStream out = new ByteArrayOutputStream(); + header.print(new PrintStream(out)); + if (!out.toString().equals(s[2])) { + throw new AssertionError("FAILED: expected: " + + s[2] + "\nReceived: " + out.toString()); + } else { + System.out.println("PASSED: ::print returned correct " + + "status line and headers:\n" + out.toString()); + } + } + } + + // Test methods URLConnection::getRequestProperties, + // ::getHeaderField, ::getHeaderFieldKey + static void testURLConnectionMethods() throws IOException { + HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); + urlConn.setRequestProperty(H1, ""); + urlConn.setRequestProperty(H1, VALUE); + urlConn.setRequestProperty(H2, null); // Expected to contain ':' between key and value + Map> props = urlConn.getRequestProperties(); + Map> expectedMap = new HashMap>(); + expectedMap.put(H1, oneList); + expectedMap.put(H2, Arrays.asList((String)null)); + + // Test request properties + System.out.println("Client request properties"); + StringBuilder sb = new StringBuilder(); + props.forEach((k, v) -> sb.append(k + ": " + + v.stream().collect(Collectors.joining()) + "\n")); + System.out.println(sb); + + if (!props.equals(expectedMap)) { + throw new AssertionError("Unexpected properties returned: " + + props); + } else { + System.out.println("Properties returned as expected"); + } + + // Test header fields + String headerField = urlConn.getHeaderField(0); + if (!headerField.contains("200 OK")) { + throw new AssertionError("Expected headerField[0]: status line. " + + "Received: " + headerField); + } else { + System.out.println("PASSED: headerField[0] contains status line: " + + headerField); + } + + String headerFieldKey = urlConn.getHeaderFieldKey(0); + if (headerFieldKey != null) { + throw new AssertionError("Expected headerFieldKey[0]: null. " + + "Received: " + headerFieldKey); + } else { + System.out.println("PASSED: headerFieldKey[0] is null"); + } + + // Check that test request headers are included with correct format + try ( + BufferedReader in = new BufferedReader( + new InputStreamReader(urlConn.getInputStream())) + ) { + if (!headers.keySet().contains(H1)) { + throw new AssertionError("Expected key not found: " + + H1 + ": " + VALUE); + } else if (!headers.get(H1).equals(oneList)) { + throw new AssertionError("Unexpected key-value pair: " + + H1 + ": " + headers.get(H1)); + } else { + System.out.println("PASSED: " + H1 + " included in request headers"); + } + + if (!headers.keySet().contains(H2)) { + throw new AssertionError("Expected key not found: " + + H2 + ": "); + // Check that empty list is returned + } else if (!headers.get(H2).equals(zeroList)) { + throw new AssertionError("Unexpected key-value pair: " + + H2 + ": " + headers.get(H2)); + } else { + System.out.println("PASSED: " + H2 + " included in request headers"); + } + + String inputLine; + while ((inputLine = in.readLine()) != null) { + System.out.println(inputLine); + } + } + } +} diff --git a/test/sun/security/ec/SignatureDigestTruncate.java b/test/sun/security/ec/SignatureDigestTruncate.java index a0ebbb2cf58d6e0167715e4dc0476e2f8adce83e..18208fc38f4143c9880c97a90dc78e6b2e6ff831 100644 --- a/test/sun/security/ec/SignatureDigestTruncate.java +++ b/test/sun/security/ec/SignatureDigestTruncate.java @@ -91,22 +91,25 @@ public class SignatureDigestTruncate { String privateKeyStr, String msgStr, String kStr, String sigStr) throws Exception { + System.out.println("Testing " + alg + " with " + curveName); + byte[] privateKey = Convert.hexStringToByteArray(privateKeyStr); byte[] msg = Convert.hexStringToByteArray(msgStr); byte[] k = Convert.hexStringToByteArray(kStr); byte[] expectedSig = Convert.hexStringToByteArray(sigStr); - AlgorithmParameters params = AlgorithmParameters.getInstance("EC"); + AlgorithmParameters params = + AlgorithmParameters.getInstance("EC", "SunEC"); params.init(new ECGenParameterSpec(curveName)); ECParameterSpec ecParams = params.getParameterSpec(ECParameterSpec.class); - KeyFactory kf = KeyFactory.getInstance("EC"); + KeyFactory kf = KeyFactory.getInstance("EC", "SunEC"); BigInteger s = new BigInteger(1, privateKey); ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(s, ecParams); PrivateKey privKey = kf.generatePrivate(privKeySpec); - Signature sig = Signature.getInstance(alg); + Signature sig = Signature.getInstance(alg, "SunEC"); sig.initSign(privKey, new FixedRandom(k)); sig.update(msg); byte[] computedSig = sig.sign(); diff --git a/test/sun/security/krb5/auto/Addresses.java b/test/sun/security/krb5/auto/Addresses.java new file mode 100644 index 0000000000000000000000000000000000000000..0bd62e496b01b5be5cdf5cf40b0ed58e6a20a0ca --- /dev/null +++ b/test/sun/security/krb5/auto/Addresses.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2012, 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 8031111 + * @summary fix krb5 caddr + * @compile -XDignore.symbol.file Addresses.java + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock Addresses + */ + +import sun.security.krb5.Config; + +import javax.security.auth.kerberos.KerberosTicket; +import java.net.Inet4Address; +import java.net.InetAddress; + +public class Addresses { + + public static void main(String[] args) throws Exception { + + KDC.saveConfig(OneKDC.KRB5_CONF, new OneKDC(null), + "noaddresses = false", + "extra_addresses = 10.0.0.10, 10.0.0.11 10.0.0.12"); + Config.refresh(); + + KerberosTicket ticket = + Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false) + .s().getPrivateCredentials(KerberosTicket.class) + .iterator().next(); + + InetAddress loopback = InetAddress.getLoopbackAddress(); + InetAddress extra1 = InetAddress.getByName("10.0.0.10"); + InetAddress extra2 = InetAddress.getByName("10.0.0.11"); + InetAddress extra3 = InetAddress.getByName("10.0.0.12"); + + boolean loopbackFound = false; + boolean extra1Found = false; + boolean extra2Found = false; + boolean extra3Found = false; + boolean networkFound = false; + + for (InetAddress ia: ticket.getClientAddresses()) { + System.out.println(ia); + if (ia.equals(loopback)) { + loopbackFound = true; + System.out.println(" loopback found"); + } else if (ia.equals(extra1)) { + extra1Found = true; + System.out.println(" extra1 found"); + } else if (ia.equals(extra2)) { + extra2Found = true; + System.out.println(" extra2 found"); + } else if (ia.equals(extra3)) { + extra3Found = true; + System.out.println(" extra3 found"); + } else if (ia instanceof Inet4Address) { + networkFound = true; + System.out.println(" another address (" + ia + + "), assumed real network"); + } + } + + if (!loopbackFound || !networkFound + || !extra1Found || !extra2Found || !extra3Found ) { + throw new Exception(); + } + } +} diff --git a/test/sun/security/krb5/auto/Basic.java b/test/sun/security/krb5/auto/Basic.java index 7ec3873fb6375cb0d81bd969598b736e8905c45d..cc934ff5b6f9d1c16e0991bad926cf81d4e6d468 100644 --- a/test/sun/security/krb5/auto/Basic.java +++ b/test/sun/security/krb5/auto/Basic.java @@ -23,10 +23,12 @@ /* * @test - * @bug 7152176 + * @bug 7152176 8201627 * @summary More krb5 tests * @compile -XDignore.symbol.file Basic.java - * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock Basic + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock + * -Dsun.security.krb5.acceptor.sequence.number.nonmutual=zero + * Basic */ import sun.security.jgss.GSSUtil; @@ -45,6 +47,7 @@ public class Basic { c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); c.x().requestCredDeleg(true); + c.x().requestMutualAuth(false); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); Context.handshake(c, s); diff --git a/test/sun/security/krb5/auto/BasicKrb5Test.java b/test/sun/security/krb5/auto/BasicKrb5Test.java index ade0b54fe38c21afe6be43eb6e87e869eae4b2a3..f18ae164245a9ae42ee37c1054475a2d7f4b3150 100644 --- a/test/sun/security/krb5/auto/BasicKrb5Test.java +++ b/test/sun/security/krb5/auto/BasicKrb5Test.java @@ -79,7 +79,7 @@ public class BasicKrb5Test { String etype = null; for (String arg: args) { if (arg.equals("-s")) Context.usingStream = true; - else if(arg.equals("-C")) conf = false; + else if (arg.equals("-C")) conf = false; else etype = arg; } diff --git a/test/sun/security/krb5/auto/BasicProc.java b/test/sun/security/krb5/auto/BasicProc.java index bcc3cd051b40dd174cea091e3a53b00fe32bb108..50f65eab52c92132198ea45dcb401629642d276b 100644 --- a/test/sun/security/krb5/auto/BasicProc.java +++ b/test/sun/security/krb5/auto/BasicProc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -23,180 +23,306 @@ /* * @test - * @bug 8009977 - * @summary A test library to launch multiple Java processes - * @library ../../../../java/security/testlibrary/ + * @bug 8009977 8186884 8201627 + * @summary A test to launch multiple Java processes using either Java GSS + * or native GSS + * @library ../../../../java/security/testlibrary /lib/testlibrary * @compile -XDignore.symbol.file BasicProc.java - * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock BasicProc + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock BasicProc launcher */ -import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.PropertyPermission; +import java.util.Set; + +import jdk.testlibrary.Asserts; import org.ietf.jgss.Oid; +import sun.security.krb5.Config; import javax.security.auth.PrivateCredentialPermission; +/** + * Run this test automatically and test Java GSS with embedded KDC. + * + * Run with customized native.krb5.libs to test interop between Java GSS + * and native GSS, and native.kdc.path with a native KDC. For example, + * run the following command to test interop among Java, default native, + * MIT, and Heimdal krb5 libraries with the Heimdal KDC: + * + * jtreg -Dnative.krb5.libs=j=, + * n=, + * k=/usr/local/krb5/lib/libgssapi_krb5.so, + * h=/space/install/heimdal/lib/libgssapi.so \ + * -Dnative.kdc.path=/usr/local/heimdal \ + * BasicProc.java + * + * Note: The first 4 lines should be concatenated to make a long system + * property value with no blank around ",". This comma-separated value + * has each element being name=libpath. The special name "j" means the + * Java library and libpath is ignored. Otherwise it means a native library, + * and libpath (can be empty) will be the value for the sun.security.jgss.lib + * system property. If this system property is not set, only the Java + * library will be tested. + */ + public class BasicProc { - static String CONF = "krb5.conf"; - static String KTAB = "ktab"; + private static final String CONF = "krb5.conf"; + private static final String KTAB_S = "server.ktab"; + private static final String KTAB_B = "backend.ktab"; + + private static final String HOST = "localhost"; + private static final String SERVER = "server/" + HOST; + private static final String BACKEND = "backend/" + HOST; + private static final String USER = "user"; + private static final char[] PASS = "password".toCharArray(); + private static final String REALM = "REALM"; + + private static final int MSGSIZE = 1024; + private static final byte[] MSG = new byte[MSGSIZE]; + public static void main(String[] args) throws Exception { - String HOST = "localhost"; - String SERVER = "server/" + HOST; - String BACKEND = "backend/" + HOST; - String USER = "user"; - char[] PASS = "password".toCharArray(); - String REALM = "REALM"; Oid oid = new Oid("1.2.840.113554.1.2.2"); + byte[] token, msg; - if (args.length == 0) { - System.setProperty("java.security.krb5.conf", CONF); - KDC kdc = KDC.create(REALM, HOST, 0, true); - kdc.addPrincipal(USER, PASS); - kdc.addPrincipalRandKey("krbtgt/" + REALM); - kdc.addPrincipalRandKey(SERVER); - kdc.addPrincipalRandKey(BACKEND); - - String cwd = System.getProperty("user.dir"); - kdc.writeKtab(KTAB); - KDC.saveConfig(CONF, kdc, "forwardable = true"); - - Proc pc = Proc.create("BasicProc") - .args("client") - .prop("java.security.krb5.conf", CONF) - .prop("java.security.manager", "") - .prop("sun.net.spi.nameservice.provider.1", "ns,mock") - .perm(new java.lang.RuntimePermission( - "accessClassInPackage.sun.net.spi.nameservice")) - .perm(new java.util.PropertyPermission( - "sun.security.krb5.principal", "read")) - .perm(new javax.security.auth.AuthPermission( - "modifyPrincipals")) - .perm(new javax.security.auth.AuthPermission( - "modifyPrivateCredentials")) - .perm(new javax.security.auth.AuthPermission("doAs")) - .perm(new javax.security.auth.kerberos.ServicePermission( - "krbtgt/" + REALM + "@" + REALM, "initiate")) - .perm(new javax.security.auth.kerberos.ServicePermission( - "server/localhost@" + REALM, "initiate")) - .perm(new javax.security.auth.kerberos.DelegationPermission( - "\"server/localhost@" + REALM + "\" " + - "\"krbtgt/" + REALM + "@" + REALM + "\"")) - .debug("C") - .start(); - Proc ps = Proc.create("BasicProc") - .args("server") - .prop("java.security.krb5.conf", CONF) - .prop("java.security.manager", "") - .prop("sun.net.spi.nameservice.provider.1", "ns,mock") - .perm(new java.lang.RuntimePermission( - "accessClassInPackage.sun.net.spi.nameservice")) - .perm(new java.util.PropertyPermission( + switch (args[0]) { + case "launcher": + KDC kdc = KDC.create(REALM, HOST, 0, true); + try { + kdc.addPrincipal(USER, PASS); + kdc.addPrincipalRandKey("krbtgt/" + REALM); + kdc.addPrincipalRandKey(SERVER); + kdc.addPrincipalRandKey(BACKEND); + + // Native lib might do some name lookup + KDC.saveConfig(CONF, kdc, + "dns_lookup_kdc = no", + "ticket_lifetime = 1h", + "dns_lookup_realm = no", + "dns_canonicalize_hostname = false", + "forwardable = true"); + System.setProperty("java.security.krb5.conf", CONF); + Config.refresh(); + kdc.writeKtab(KTAB_S, false, SERVER); + kdc.writeKtab(KTAB_B, false, BACKEND); + + String[] tmp = System.getProperty("native.krb5.libs", "j=") + .split(","); + + // Library paths. The 1st one is always null which means + // Java, "" means the default native lib. + String[] libs = new String[tmp.length]; + + // Names for each lib above. Use in file names. + String[] names = new String[tmp.length]; + + boolean hasNative = false; + + for (int i = 0; i < tmp.length; i++) { + if (tmp[i].isEmpty()) { + throw new Exception("Invalid native.krb5.libs"); + } + String[] pair = tmp[i].split("=", 2); + names[i] = pair[0]; + if (!pair[0].equals("j")) { + libs[i] = pair.length > 1 ? pair[1] : ""; + hasNative = true; + } + } + + if (hasNative) { + kdc.kinit(USER, "base.ccache"); + } + + // Try the same lib first + for (int i = 0; i < libs.length; i++) { + once(names[i] + names[i] + names[i], + libs[i], libs[i], libs[i]); + } + + for (int i = 0; i < libs.length; i++) { + for (int j = 0; j < libs.length; j++) { + for (int k = 0; k < libs.length; k++) { + if (i != j || i != k) { + once(names[i] + names[j] + names[k], + libs[i], libs[j], libs[k]); + } + } + } + } + } finally { + kdc.terminate(); + } + break; + case "client": + Context c = args[1].equals("n") ? + Context.fromThinAir() : + Context.fromUserPass(USER, PASS, false); + c.startAsClient(SERVER, oid); + c.x().requestCredDeleg(true); + c.x().requestMutualAuth(true); + Proc.binOut(c.take(new byte[0])); // AP-REQ + c.take(Proc.binIn()); // AP-REP + Proc.binOut(c.wrap(MSG, true)); + Proc.binOut(c.getMic(MSG)); + break; + case "server": + Context s = args[1].equals("n") ? + Context.fromThinAir() : + Context.fromUserKtab(SERVER, KTAB_S, true); + s.startAsServer(oid); + token = Proc.binIn(); // AP-REQ + Proc.binOut(s.take(token)); // AP-REP + msg = s.unwrap(Proc.binIn(), true); + Asserts.assertTrue(Arrays.equals(msg, MSG)); + s.verifyMic(Proc.binIn(), msg); + Context s2 = s.delegated(); + s2.startAsClient(BACKEND, oid); + s2.x().requestMutualAuth(false); + Proc.binOut(s2.take(new byte[0])); // AP-REQ + msg = s2.unwrap(Proc.binIn(), true); + Asserts.assertTrue(Arrays.equals(msg, MSG)); + s2.verifyMic(Proc.binIn(), msg); + break; + case "backend": + Context b = args[1].equals("n") ? + Context.fromThinAir() : + Context.fromUserKtab(BACKEND, KTAB_B, true); + b.startAsServer(oid); + token = b.take(Proc.binIn()); // AP-REQ + Asserts.assertTrue(token == null); + Proc.binOut(b.wrap(MSG, true)); + Proc.binOut(b.getMic(MSG)); + break; + } + } + + /** + * One test run. + * + * @param label test label + * @param lc lib of client + * @param ls lib of server + * @param lb lib of backend + */ + private static void once(String label, String lc, String ls, String lb) + throws Exception { + + Proc pc = proc(lc) + .args("client", lc == null ? "j" : "n") + .perm(new javax.security.auth.kerberos.ServicePermission( + "krbtgt/" + REALM + "@" + REALM, "initiate")) + .perm(new javax.security.auth.kerberos.ServicePermission( + SERVER + "@" + REALM, "initiate")) + .perm(new javax.security.auth.kerberos.DelegationPermission( + "\"" + SERVER + "@" + REALM + "\" " + + "\"krbtgt/" + REALM + "@" + REALM + "\"")) + .debug(label + "-C"); + if (lc == null) { + // for Krb5LoginModule::promptForName + pc.perm(new PropertyPermission("user.name", "read")); + } else { + Files.copy(Paths.get("base.ccache"), Paths.get(label + ".ccache")); + Set perms = new HashSet<>(); + perms.add(PosixFilePermission.OWNER_READ); + perms.add(PosixFilePermission.OWNER_WRITE); + Files.setPosixFilePermissions(Paths.get(label + ".ccache"), + Collections.unmodifiableSet(perms)); + pc.env("KRB5CCNAME", label + ".ccache"); + // Do not try system ktab if ccache fails + pc.env("KRB5_KTNAME", "none"); + } + pc.start(); + + Proc ps = proc(ls) + .args("server", ls == null ? "j" : "n") + .perm(new javax.security.auth.kerberos.ServicePermission( + SERVER + "@" + REALM, "accept")) + .perm(new javax.security.auth.kerberos.ServicePermission( + BACKEND + "@" + REALM, "initiate")) + .debug(label + "-S"); + if (ls == null) { + ps.perm(new PrivateCredentialPermission( + "javax.security.auth.kerberos.KeyTab * \"*\"", "read")) + .perm(new java.io.FilePermission(KTAB_S, "read")); + } else { + ps.env("KRB5_KTNAME", KTAB_S); + } + ps.start(); + + Proc pb = proc(lb) + .args("backend", lb == null ? "j" : "n") + .perm(new javax.security.auth.kerberos.ServicePermission( + BACKEND + "@" + REALM, "accept")) + .debug(label + "-B"); + if (lb == null) { + pb.perm(new PrivateCredentialPermission( + "javax.security.auth.kerberos.KeyTab * \"*\"", "read")) + .perm(new java.io.FilePermission(KTAB_B, "read")); + } else { + pb.env("KRB5_KTNAME", KTAB_B); + } + pb.start(); + + // Client and server + ps.println(pc.readData()); // AP-REQ + pc.println(ps.readData()); // AP-REP + + ps.println(pc.readData()); // KRB-PRIV + ps.println(pc.readData()); // KRB-SAFE + + // Server and backend + pb.println(ps.readData()); // AP-REQ + + ps.println(pb.readData()); // KRB-PRIV + ps.println(pb.readData()); // KRB-SAFE + + if ((pc.waitFor() | ps.waitFor() | pb.waitFor()) != 0) { + throw new Exception("Process failed"); + } + } + + /** + * A Proc for a child process. + * + * @param lib the library. Null is Java. "" is default native lib. + */ + private static Proc proc(String lib) throws Exception { + Proc p = Proc.create("BasicProc") + .prop("java.security.manager", "") + .prop("sun.net.spi.nameservice.provider.1", "ns,mock") + .perm(new javax.security.auth.AuthPermission("doAs")); + if (lib != null) { + p.env("KRB5_CONFIG", CONF) + .env("KRB5_TRACE", "/dev/stderr") + .prop("sun.security.jgss.native", "true") + .prop("sun.security.jgss.lib", lib) + .prop("javax.security.auth.useSubjectCredsOnly", "false") + .prop("sun.security.nativegss.debug", "true"); + int pos = lib.lastIndexOf('/'); + if (pos > 0) { + p.env("LD_LIBRARY_PATH", lib.substring(0, pos)); + p.env("DYLD_LIBRARY_PATH", lib.substring(0, pos)); + } + } else { + p.perm(new java.util.PropertyPermission( "sun.security.krb5.principal", "read")) - .perm(new javax.security.auth.AuthPermission( - "modifyPrincipals")) - .perm(new javax.security.auth.AuthPermission( - "modifyPrivateCredentials")) - .perm(new javax.security.auth.AuthPermission("doAs")) - .perm(new PrivateCredentialPermission( - "javax.security.auth.kerberos.KeyTab * \"*\"", - "read")) - .perm(new javax.security.auth.kerberos.ServicePermission( - "server/localhost@" + REALM, "accept")) - .perm(new java.io.FilePermission( - cwd + File.separator + KTAB, "read")) - .perm(new javax.security.auth.kerberos.ServicePermission( - "backend/localhost@" + REALM, "initiate")) - .debug("S") - .start(); - Proc pb = Proc.create("BasicProc") - .args("backend") - .prop("java.security.krb5.conf", CONF) - .prop("java.security.manager", "") - .prop("sun.net.spi.nameservice.provider.1", "ns,mock") + // For Krb5LoginModule::login. .perm(new java.lang.RuntimePermission( "accessClassInPackage.sun.net.spi.nameservice")) - .perm(new java.util.PropertyPermission( - "sun.security.krb5.principal", "read")) .perm(new javax.security.auth.AuthPermission( "modifyPrincipals")) .perm(new javax.security.auth.AuthPermission( "modifyPrivateCredentials")) - .perm(new javax.security.auth.AuthPermission("doAs")) - .perm(new PrivateCredentialPermission( - "javax.security.auth.kerberos.KeyTab * \"*\"", - "read")) - .perm(new javax.security.auth.kerberos.ServicePermission( - "backend/localhost@" + REALM, "accept")) - .perm(new java.io.FilePermission( - cwd + File.separator + KTAB, "read")) - .debug("B") - .start(); - - // Client and server handshake - String token = pc.readData(); - ps.println(token); - token = ps.readData(); - pc.println(token); - // Server and backend handshake - token = ps.readData(); - pb.println(token); - token = pb.readData(); - ps.println(token); - // wrap/unwrap/getMic/verifyMic and plain text - token = ps.readData(); - pb.println(token); - token = pb.readData(); - ps.println(token); - token = pb.readData(); - ps.println(token); - - if ((pc.waitFor() | ps.waitFor() | pb.waitFor()) != 0) { - throw new Exception(); - } - } else if (args[0].equals("client")) { - Context c = Context.fromUserPass(USER, PASS, false); - c.startAsClient(SERVER, oid); - c.x().requestCredDeleg(true); - Proc.binOut(c.take(new byte[0])); - byte[] token = Proc.binIn(); - c.take(token); - } else if (args[0].equals("server")) { - Context s = Context.fromUserKtab(SERVER, KTAB, true); - s.startAsServer(oid); - byte[] token = Proc.binIn(); - token = s.take(token); - Proc.binOut(token); - Context s2 = s.delegated(); - s2.startAsClient(BACKEND, oid); - Proc.binOut(s2.take(new byte[0])); - token = Proc.binIn(); - s2.take(token); - byte[] msg = "Hello".getBytes(); - Proc.binOut(s2.wrap(msg, true)); - s2.verifyMic(Proc.binIn(), msg); - String in = Proc.textIn(); - if (!in.equals("Hello")) { - throw new Exception(); - } - } else if (args[0].equals("backend")) { - Context b = Context.fromUserKtab(BACKEND, KTAB, true); - b.startAsServer(oid); - byte[] token = Proc.binIn(); - Proc.binOut(b.take(token)); - byte[] msg = b.unwrap(Proc.binIn(), true); - Proc.binOut(b.getMic(msg)); - Proc.textOut(new String(msg)); + .prop("sun.security.krb5.debug", "true") + .prop("java.security.krb5.conf", CONF); } - } - // create a native server - private static Proc ns(Proc p) throws Exception { - return p - .env("KRB5_CONFIG", CONF) - .env("KRB5_KTNAME", KTAB) - .prop("sun.net.spi.nameservice.provider.1", "ns,mock") - .prop("sun.security.jgss.native", "true") - .prop("javax.security.auth.useSubjectCredsOnly", "false") - .prop("sun.security.nativegss.debug", "true"); + return p; } } diff --git a/test/sun/security/krb5/auto/Context.java b/test/sun/security/krb5/auto/Context.java index f6646055aea3f1d54a1344ee04fbcda63d66b6bc..2c4915393cdc888c6f1704a4f990302f18eb96fc 100644 --- a/test/sun/security/krb5/auto/Context.java +++ b/test/sun/security/krb5/auto/Context.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2018, 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 @@ -22,14 +22,21 @@ */ import com.sun.security.auth.module.Krb5LoginModule; -import java.security.Key; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.security.Key; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.Set; import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.kerberos.KerberosKey; import javax.security.auth.kerberos.KerberosTicket; import javax.security.auth.login.LoginContext; @@ -40,6 +47,10 @@ import org.ietf.jgss.GSSManager; import org.ietf.jgss.GSSName; import org.ietf.jgss.MessageProp; import org.ietf.jgss.Oid; +import sun.security.jgss.krb5.Krb5Util; +import sun.security.krb5.Credentials; +import sun.security.krb5.internal.ccache.CredentialsCache; + import com.sun.security.jgss.ExtendedGSSContext; import com.sun.security.jgss.InquireType; import com.sun.security.jgss.AuthorizationDataEntry; @@ -154,24 +165,36 @@ public class Context { Map map = new HashMap<>(); Map shared = new HashMap<>(); + if (storeKey) { + map.put("storeKey", "true"); + } + if (pass != null) { - map.put("useFirstPass", "true"); - shared.put("javax.security.auth.login.name", user); - shared.put("javax.security.auth.login.password", pass); + krb5.initialize(out.s, new CallbackHandler() { + @Override + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + ((NameCallback)cb).setName(user); + } else if (cb instanceof PasswordCallback) { + ((PasswordCallback)cb).setPassword(pass); + } + } + } + }, shared, map); } else { map.put("doNotPrompt", "true"); map.put("useTicketCache", "true"); if (user != null) { map.put("principal", user); } - } - if (storeKey) { - map.put("storeKey", "true"); + krb5.initialize(out.s, null, shared, map); } - krb5.initialize(out.s, null, shared, map); krb5.login(); krb5.commit(); + return out; } @@ -452,18 +475,21 @@ public class Context { out = me.x.wrap(input, 0, input.length, p1); } System.out.println(printProp(p1)); + if ((x.getConfState() && privacy) != p1.getPrivacy()) { + throw new Exception("unexpected privacy status"); + } return out; } }, t); } - public byte[] unwrap(byte[] t, final boolean privacy) + public byte[] unwrap(byte[] t, final boolean privacyExpected) throws Exception { return doAs(new Action() { @Override public byte[] run(Context me, byte[] input) throws Exception { - System.out.printf("unwrap %s privacy from %s: ", privacy?"with":"without", me.name); - MessageProp p1 = new MessageProp(0, privacy); + System.out.printf("unwrap from %s", me.name); + MessageProp p1 = new MessageProp(0, true); byte[] bytes; if (usingStream) { ByteArrayOutputStream os = new ByteArrayOutputStream(); @@ -473,6 +499,9 @@ public class Context { bytes = me.x.unwrap(input, 0, input.length, p1); } System.out.println(printProp(p1)); + if (p1.getPrivacy() != privacyExpected) { + throw new Exception("Unexpected privacy: " + p1.getPrivacy()); + } return bytes; } }, t); @@ -514,6 +543,10 @@ public class Context { p1); } System.out.println(printProp(p1)); + if (p1.isUnseqToken() || p1.isOldToken() + || p1.isDuplicateToken() || p1.isGapToken()) { + throw new Exception("Wrong sequence number detected"); + } return null; } }, t); @@ -529,13 +562,27 @@ public class Context { * @param s2 the receiver * @throws java.lang.Exception If anything goes wrong */ - static public void transmit(final String message, final Context s1, + static public void transmit(String message, final Context s1, + final Context s2) throws Exception { + transmit(message.getBytes(), s1, s2); + } + + /** + * Transmits a message from one Context to another. The sender wraps the + * message and sends it to the receiver. The receiver unwraps it, creates + * a MIC of the clear text and sends it back to the sender. The sender + * verifies the MIC against the message sent earlier. + * @param messageBytes the message + * @param s1 the sender + * @param s2 the receiver + * @throws java.lang.Exception If anything goes wrong + */ + static public void transmit(byte[] messageBytes, final Context s1, final Context s2) throws Exception { - final byte[] messageBytes = message.getBytes(); System.out.printf("-------------------- TRANSMIT from %s to %s------------------------\n", s1.name, s2.name); byte[] wrapped = s1.wrap(messageBytes, true); - byte[] unwrapped = s2.unwrap(wrapped, true); + byte[] unwrapped = s2.unwrap(wrapped, s2.x.getConfState()); if (!Arrays.equals(messageBytes, unwrapped)) { throw new Exception("wrap/unwrap mismatch"); } @@ -615,6 +662,32 @@ public class Context { }, in); } + /** + * Saves the tickets to a ccache file. + * + * @param file pathname of the ccache file + * @return true if created, false otherwise. + */ + public boolean ccache(String file) throws Exception { + Set tickets + = s.getPrivateCredentials(KerberosTicket.class); + if (tickets != null && !tickets.isEmpty()) { + CredentialsCache cc = null; + for (KerberosTicket t : tickets) { + Credentials cred = Krb5Util.ticketToCreds(t); + if (cc == null) { + cc = CredentialsCache.create(cred.getClient(), file); + } + cc.update(cred.toCCacheCreds()); + } + if (cc != null) { + cc.save(); + return true; + } + } + return false; + } + /** * Handshake (security context establishment process) between two Contexts * @param c the initiator diff --git a/test/sun/security/krb5/auto/DiffSaltParams.java b/test/sun/security/krb5/auto/DiffSaltParams.java new file mode 100644 index 0000000000000000000000000000000000000000..275b82709826a9424ce010d2a545678e62875abd --- /dev/null +++ b/test/sun/security/krb5/auto/DiffSaltParams.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017, 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 8186831 + * @summary Kerberos ignores PA-DATA with a non-null s2kparams + * @compile -XDignore.symbol.file DiffSaltParams.java + * @run main/othervm -Dsun.security.krb5.debug=true -Dsun.net.spi.nameservice.provider.1=ns,mock DiffSaltParams + */ + +public class DiffSaltParams { + + public static void main(String[] args) throws Exception { + + OneKDC kdc = new OneKDC(null).writeJAASConf(); + kdc.addPrincipal("user1", "user1pass".toCharArray(), + "hello", new byte[]{0, 0, 1, 0}); + kdc.addPrincipal("user2", "user2pass".toCharArray(), + "hello", null); + kdc.addPrincipal("user3", "user3pass".toCharArray(), + null, new byte[]{0, 0, 1, 0}); + kdc.addPrincipal("user4", "user4pass".toCharArray()); + + Context.fromUserPass("user1", "user1pass".toCharArray(), true); + Context.fromUserPass("user2", "user2pass".toCharArray(), true); + Context.fromUserPass("user3", "user3pass".toCharArray(), true); + Context.fromUserPass("user4", "user4pass".toCharArray(), true); + } +} diff --git a/test/sun/security/krb5/auto/Forwarded.java b/test/sun/security/krb5/auto/Forwarded.java new file mode 100644 index 0000000000000000000000000000000000000000..0bdc3f5ebb73425dbe43916f808a7750eee2aa7b --- /dev/null +++ b/test/sun/security/krb5/auto/Forwarded.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 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 8031111 + * @summary fix krb5 caddr + * @compile -XDignore.symbol.file Forwarded.java + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock Forwarded + */ + +import sun.security.jgss.GSSUtil; +import sun.security.krb5.internal.KDCOptions; +import sun.security.krb5.internal.KDCReqBody; +import sun.security.krb5.internal.TGSReq; + +public class Forwarded { + + public static void main(String[] args) throws Exception { + + new OneKDC(null).setOption(KDC.Option.CHECK_ADDRESSES, true); + + Context c; + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + c.x().requestCredDeleg(true); + + c.take(new byte[0]); + } +} diff --git a/test/sun/security/krb5/auto/KDC.java b/test/sun/security/krb5/auto/KDC.java index 02a363d5d3058c2eb0691fe2cc2d1c21fcc6dbd7..0c5a8916644336227fe127f937a9ced2c26f548a 100644 --- a/test/sun/security/krb5/auto/KDC.java +++ b/test/sun/security/krb5/auto/KDC.java @@ -27,19 +27,19 @@ import java.lang.reflect.InvocationTargetException; import java.net.*; import java.io.*; import java.lang.reflect.Method; -import java.security.SecureRandom; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalAmount; -import java.time.temporal.TemporalUnit; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; import sun.net.spi.nameservice.NameService; import sun.net.spi.nameservice.NameServiceDescriptor; import sun.security.krb5.*; import sun.security.krb5.internal.*; import sun.security.krb5.internal.ccache.CredentialsCache; +import sun.security.krb5.internal.crypto.EType; import sun.security.krb5.internal.crypto.KeyUsage; import sun.security.krb5.internal.ktab.KeyTab; import sun.security.util.DerInputStream; @@ -50,6 +50,11 @@ import java.util.regex.Pattern; /** * A KDC server. + * + * Note: By setting the system property native.kdc.path to a native + * krb5 installation, this class starts a native KDC with the + * given realm and host. It can also add new principals and save keytabs. + * Other features might not be available. *

      * Features: *

        @@ -127,13 +132,21 @@ import java.util.regex.Pattern; */ public class KDC { - // Under the hood. - public static final int DEFAULT_LIFETIME = 39600; public static final int DEFAULT_RENEWTIME = 86400; - // The random generator to generate random keys (including session keys) - private static SecureRandom secureRandom = new SecureRandom(); + // What etypes the KDC supports. Comma-separated strings. Null for all. + // Please note native KDCs might use different names. + private static final String SUPPORTED_ETYPES + = System.getProperty("kdc.supported.enctypes"); + + // The native KDC + private final NativeKdc nativeKdc; + + // The native KDC process + private Process kdcProc = null; + + // Under the hood. // Principal db. principal -> pass. A case-insensitive TreeMap is used // so that even if the client provides a name with different case, the KDC @@ -141,6 +154,25 @@ public class KDC { private TreeMap passwords = new TreeMap<> (String.CASE_INSENSITIVE_ORDER); + // Non default salts. Precisely, there should be different salts for + // different etypes, pretend they are the same at the moment. + private TreeMap salts = new TreeMap<> + (String.CASE_INSENSITIVE_ORDER); + + // Non default s2kparams for newer etypes. Precisely, there should be + // different s2kparams for different etypes, pretend they are the same + // at the moment. + private TreeMap s2kparamses = new TreeMap<> + (String.CASE_INSENSITIVE_ORDER); + + // Alias for referrals. + private TreeMap aliasReferrals = new TreeMap<> + (String.CASE_INSENSITIVE_ORDER); + + // Alias for local resolution. + private TreeMap alias2Principals = new TreeMap<> + (String.CASE_INSENSITIVE_ORDER); + // Realm name private String realm; // KDC @@ -213,6 +245,10 @@ public class KDC { * Sensitive accounts can never be delegated. */ SENSITIVE_ACCOUNTS, + /** + * If true, will check if TGS-REQ contains a non-null addresses field. + */ + CHECK_ADDRESSES, }; //static { @@ -223,7 +259,8 @@ public class KDC { * A standalone KDC server. */ public static void main(String[] args) throws Exception { - KDC kdc = create("RABBIT.HOLE", "kdc.rabbit.hole", 0, false); + int port = args.length > 0 ? Integer.parseInt(args[0]) : 0; + KDC kdc = create("RABBIT.HOLE", "kdc.rabbit.hole", port, false); kdc.addPrincipal("dummy", "bogus".toCharArray()); kdc.addPrincipal("foo", "bar".toCharArray()); kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE"); @@ -257,7 +294,8 @@ public class KDC { * @return the running KDC instance * @throws java.io.IOException for any socket creation error */ - public static KDC create(String realm, String kdc, int port, boolean asDaemon) throws IOException { + public static KDC create(String realm, String kdc, int port, + boolean asDaemon) throws IOException { return new KDC(realm, kdc, port, asDaemon); } @@ -297,26 +335,38 @@ public class KDC { */ public void writeKtab(String tab, boolean append, String... names) throws IOException, KrbException { - KeyTab ktab = append ? KeyTab.getInstance(tab) : KeyTab.create(tab); + KeyTab ktab = null; + if (nativeKdc == null) { + ktab = append ? KeyTab.getInstance(tab) : KeyTab.create(tab); + } Iterable entries = (names.length != 0) ? Arrays.asList(names): passwords.keySet(); for (String name : entries) { - char[] pass = passwords.get(name); - int kvno = 0; - if (Character.isDigit(pass[pass.length-1])) { - kvno = pass[pass.length-1] - '0'; + if (name.indexOf('@') < 0) { + name = name + "@" + realm; } - PrincipalName pn = new PrincipalName(name, + if (nativeKdc == null) { + char[] pass = passwords.get(name); + int kvno = 0; + if (Character.isDigit(pass[pass.length - 1])) { + kvno = pass[pass.length - 1] - '0'; + } + PrincipalName pn = new PrincipalName(name, name.indexOf('/') < 0 ? - PrincipalName.KRB_NT_UNKNOWN : - PrincipalName.KRB_NT_SRV_HST); - ktab.addEntry(pn, + PrincipalName.KRB_NT_UNKNOWN : + PrincipalName.KRB_NT_SRV_HST); + ktab.addEntry(pn, getSalt(pn), pass, kvno, true); + } else { + nativeKdc.ktadd(name, tab); + } + } + if (nativeKdc == null) { + ktab.save(); } - ktab.save(); } /** @@ -362,10 +412,36 @@ public class KDC { * @param pass the password for the principal */ public void addPrincipal(String user, char[] pass) { + addPrincipal(user, pass, null, null); + } + + /** + * Adds a new principal to this realm with a given password. + * @param user the principal's name. For a service principal, use the + * form of host/f.q.d.n + * @param pass the password for the principal + * @param salt the salt, or null if a default value will be used + * @param s2kparams the s2kparams, or null if a default value will be used + */ + public void addPrincipal( + String user, char[] pass, String salt, byte[] s2kparams) { if (user.indexOf('@') < 0) { user = user + "@" + realm; } - passwords.put(user, pass); + if (nativeKdc != null) { + if (!user.equals("krbtgt/" + realm)) { + nativeKdc.addPrincipal(user, new String(pass)); + } + passwords.put(user, new char[0]); + } else { + passwords.put(user, pass); + if (salt != null) { + salts.put(user, salt); + } + if (s2kparams != null) { + s2kparamses.put(user, s2kparams); + } + } } /** @@ -461,12 +537,11 @@ public class KDC { */ public static void saveConfig(String file, KDC kdc, Object... more) throws IOException { - File f = new File(file); StringBuffer sb = new StringBuffer(); sb.append("[libdefaults]\ndefault_realm = "); sb.append(kdc.realm); sb.append("\n"); - for (Object o: more) { + for (Object o : more) { if (o instanceof String) { sb.append(o); sb.append("\n"); @@ -474,14 +549,12 @@ public class KDC { } sb.append("\n[realms]\n"); sb.append(kdc.realmLine()); - for (Object o: more) { + for (Object o : more) { if (o instanceof KDC) { - sb.append(((KDC)o).realmLine()); + sb.append(((KDC) o).realmLine()); } } - FileOutputStream fos = new FileOutputStream(f); - fos.write(sb.toString().getBytes()); - fos.close(); + Files.write(Paths.get(file), sb.toString().getBytes()); } /** @@ -492,6 +565,29 @@ public class KDC { return port; } + /** + * Register an alias name to be referred to a different KDC for + * resolution, according to RFC 6806. + * @param alias Alias name (i.e. user@REALM.COM). + * @param referredKDC KDC to which the alias is referred for resolution. + */ + public void registerAlias(String alias, KDC referredKDC) { + aliasReferrals.remove(alias); + aliasReferrals.put(alias, referredKDC); + } + + /** + * Register an alias to be resolved to a Principal Name locally, + * according to RFC 6806. + * @param alias Alias name (i.e. user@REALM.COM). + * @param user Principal Name to which the alias is resolved. + */ + public void registerAlias(String alias, String user) + throws RealmException { + alias2Principals.remove(alias); + alias2Principals.put(alias, new PrincipalName(user)); + } + // Private helper methods /** @@ -501,6 +597,7 @@ public class KDC { private KDC(String realm, String kdc) { this.realm = realm; this.kdc = kdc; + this.nativeKdc = null; } /** @@ -508,7 +605,9 @@ public class KDC { */ protected KDC(String realm, String kdc, int port, boolean asDaemon) throws IOException { - this(realm, kdc); + this.realm = realm; + this.kdc = kdc; + this.nativeKdc = NativeKdc.get(this); startServer(port, asDaemon); } /** @@ -517,8 +616,9 @@ public class KDC { */ private static char[] randomPassword() { char[] pass = new char[32]; + Random r = new Random(); for (int i=0; i<31; i++) - pass[i] = (char)secureRandom.nextInt(); + pass[i] = (char)('a' + r.nextInt(26)); // The last char cannot be a number, otherwise, keyForUser() // believes it's a sign of kvno pass[31] = 'Z'; @@ -580,6 +680,9 @@ public class KDC { if (p.getRealmString() == null) { pn = pn + "@" + getRealm(); } + if (salts.containsKey(pn)) { + return salts.get(pn); + } if (passwords.containsKey(pn)) { try { // Find the principal name with correct case. @@ -596,6 +699,29 @@ public class KDC { return s; } + /** + * Returns the s2kparams for the principal given the etype. + * @param p principal + * @param etype encryption type + * @return the s2kparams, might be null + */ + protected byte[] getParams(PrincipalName p, int etype) { + switch (etype) { + case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: + case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: + String pn = p.toString(); + if (p.getRealmString() == null) { + pn = pn + "@" + getRealm(); + } + if (s2kparamses.containsKey(pn)) { + return s2kparamses.get(pn); + } + return new byte[] {0, 0, 0x10, 0}; + default: + return null; + } + } + /** * Returns the key for a given principal of the given encryption type * @param p the principal @@ -604,7 +730,7 @@ public class KDC { * @return the key * @throws sun.security.krb5.KrbException for unknown/unsupported etype */ - private EncryptionKey keyForUser(PrincipalName p, int etype, boolean server) + EncryptionKey keyForUser(PrincipalName p, int etype, boolean server) throws KrbException { try { // Do not call EncryptionKey.acquireSecretKeys(), otherwise @@ -619,7 +745,7 @@ public class KDC { } } return new EncryptionKey(EncryptionKeyDotStringToKey( - getPassword(p, server), getSalt(p), null, etype), + getPassword(p, server), getSalt(p), getParams(p, etype), etype), etype, kvno); } catch (KrbException ke) { throw ke; @@ -668,17 +794,36 @@ public class KDC { " sends TGS-REQ for " + service + ", " + tgsReq.reqBody.kdcOptions); KDCReqBody body = tgsReq.reqBody; - int[] eTypes = KDCReqBodyDotEType(body); + int[] eTypes = filterSupported(KDCReqBodyDotEType(body)); + if (eTypes.length == 0) { + throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP); + } int e2 = eTypes[0]; // etype for outgoing session key int e3 = eTypes[0]; // etype for outgoing ticket - PAData[] pas = KDCReqDotPAData(tgsReq); + PAData[] pas = tgsReq.pAData; Ticket tkt = null; EncTicketPart etp = null; PrincipalName cname = null; boolean allowForwardable = true; + boolean isReferral = false; + if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { + System.out.println(realm + "> verifying referral for " + + body.sname.getNameString()); + KDC referral = aliasReferrals.get(body.sname.getNameString()); + if (referral != null) { + service = new PrincipalName( + PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + + referral.getRealm(), PrincipalName.KRB_NT_SRV_INST, + this.getRealm()); + System.out.println(realm + "> referral to " + + referral.getRealm()); + isReferral = true; + } + } if (pas == null || pas.length == 0) { throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP); @@ -687,7 +832,6 @@ public class KDC { for (PAData pa: pas) { if (pa.getType() == Krb5.PA_TGS_REQ) { APReq apReq = new APReq(pa.getValue()); - EncryptedData ed = apReq.authenticator; tkt = apReq.ticket; int te = tkt.encPart.getEType(); EncryptionKey kkey = keyForUser(tkt.sname, te, true); @@ -705,13 +849,14 @@ public class KDC { PAForUserEnc p4u = new PAForUserEnc( new DerValue(pa.getValue()), null); forUserCName = p4u.name; - System.out.println(realm + "> presenting a PA_FOR_USER " + System.out.println(realm + "> See PA_FOR_USER " + " in the name of " + p4u.name); } } } if (forUserCName != null) { - List names = (List)options.get(Option.ALLOW_S4U2SELF); + List names = (List) + options.get(Option.ALLOW_S4U2SELF); if (!names.contains(cname.toString())) { // Mimic the normal KDC behavior. When a server is not // allowed to send S4U2self, do not send an error. @@ -732,11 +877,19 @@ public class KDC { EncryptionKey key = generateRandomKey(e2); // Check time, TODO + KerberosTime from = body.from; KerberosTime till = body.till; + if (from == null || from.isZero()) { + from = timeAfter(0); + } + KerberosTime rtime = body.rtime; if (till == null) { throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO } else if (till.isZero()) { - till = new KerberosTime(new Date().getTime() + 1000 * 3600 * 11); + till = timeAfter(DEFAULT_LIFETIME); + } + if (rtime == null && body.kdcOptions.get(KDCOptions.RENEWABLE)) { + rtime = timeAfter(DEFAULT_RENEWTIME); } boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; @@ -750,13 +903,19 @@ public class KDC { bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; } } + // We do not request for addresses for FORWARDED tickets + if (options.containsKey(Option.CHECK_ADDRESSES) + && body.kdcOptions.get(KDCOptions.FORWARDED) + && body.addresses != null) { + throw new KrbException(Krb5.KDC_ERR_BADOPTION); + } if (body.kdcOptions.get(KDCOptions.FORWARDED) || etp.flags.get(Krb5.TKT_OPTS_FORWARDED)) { bFlags[Krb5.TKT_OPTS_FORWARDED] = true; } if (body.kdcOptions.get(KDCOptions.RENEWABLE)) { bFlags[Krb5.TKT_OPTS_RENEWABLE] = true; - //renew = new KerberosTime(new Date().getTime() + 1000 * 3600 * 24 * 7); + //renew = timeAfter(3600 * 24 * 7); } if (body.kdcOptions.get(KDCOptions.PROXIABLE)) { bFlags[Krb5.TKT_OPTS_PROXIABLE] = true; @@ -767,7 +926,8 @@ public class KDC { if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) { bFlags[Krb5.TKT_OPTS_MAY_POSTDATE] = true; } - if (body.kdcOptions.get(KDCOptions.CNAME_IN_ADDL_TKT)) { + if (body.kdcOptions.get(KDCOptions.CNAME_IN_ADDL_TKT) && + !isReferral) { if (!options.containsKey(Option.ALLOW_S4U2PROXY)) { // Don't understand CNAME_IN_ADDL_TKT throw new KrbException(Krb5.KDC_ERR_BADOPTION); @@ -775,7 +935,8 @@ public class KDC { Map> map = (Map>) options.get(Option.ALLOW_S4U2PROXY); Ticket second = KDCReqBodyDotFirstAdditionalTicket(body); - EncryptionKey key2 = keyForUser(second.sname, second.encPart.getEType(), true); + EncryptionKey key2 = keyForUser( + second.sname, second.encPart.getEType(), true); byte[] bb = second.encPart.decrypt(key2, KeyUsage.KU_TICKET); DerInputStream derIn = new DerInputStream(bb); DerValue der = derIn.getDerValue(); @@ -807,19 +968,29 @@ public class KDC { } bFlags[Krb5.TKT_OPTS_INITIAL] = true; + KerberosTime renewTill = etp.renewTill; + if (renewTill != null && body.kdcOptions.get(KDCOptions.RENEW)) { + // till should never pass renewTill + if (till.greaterThan(renewTill)) { + till = renewTill; + } + if (System.getProperty("test.set.null.renew") != null) { + // Testing 8186576, see NullRenewUntil.java. + renewTill = null; + } + } + TicketFlags tFlags = new TicketFlags(bFlags); EncTicketPart enc = new EncTicketPart( tFlags, key, cname, new TransitedEncoding(1, new byte[0]), // TODO - new KerberosTime(new Date()), - body.from, - till, body.rtime, - body.addresses != null // always set caddr - ? body.addresses - : new HostAddresses( - new InetAddress[]{InetAddress.getLocalHost()}), + timeAfter(0), + from, + till, renewTill, + body.addresses != null ? body.addresses + : etp.caddr, null); EncryptionKey skey = keyForUser(service, e3, true); if (skey == null) { @@ -833,23 +1004,22 @@ public class KDC { ); EncTGSRepPart enc_part = new EncTGSRepPart( key, - new LastReq(new LastReqEntry[]{ - new LastReqEntry(0, new KerberosTime(new Date().getTime() - 10000)) + new LastReq(new LastReqEntry[] { + new LastReqEntry(0, timeAfter(-10)) }), body.getNonce(), // TODO: detect replay - new KerberosTime(new Date().getTime() + 1000 * 3600 * 24), + timeAfter(3600 * 24), // Next 5 and last MUST be same with ticket tFlags, - new KerberosTime(new Date()), - body.from, - till, body.rtime, + timeAfter(0), + from, + till, renewTill, service, - body.addresses != null // always set caddr - ? body.addresses - : new HostAddresses( - new InetAddress[]{InetAddress.getLocalHost()}) + body.addresses, + null ); - EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY); + EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), + KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY); TGSRep tgsRep = new TGSRep(null, cname, t, @@ -870,7 +1040,7 @@ public class KDC { + " " +ke.returnCodeMessage()); if (kerr == null) { kerr = new KRBError(null, null, null, - new KerberosTime(new Date()), + timeAfter(0), 0, ke.returnCode(), body.cname, @@ -890,6 +1060,7 @@ public class KDC { */ protected byte[] processAsReq(byte[] in) throws Exception { ASReq asReq = new ASReq(in); + byte[] asReqbytes = asReq.asn1Encode(); int[] eTypes = null; List outPAs = new ArrayList<>(); @@ -906,9 +1077,29 @@ public class KDC { KDCReqBody body = asReq.reqBody; - eTypes = KDCReqBodyDotEType(body); + eTypes = filterSupported(KDCReqBodyDotEType(body)); + if (eTypes.length == 0) { + throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP); + } int eType = eTypes[0]; + if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { + PrincipalName principal = alias2Principals.get( + body.cname.getNameString()); + if (principal != null) { + body.cname = principal; + } else { + KDC referral = aliasReferrals.get(body.cname.getNameString()); + if (referral != null) { + body.cname = new PrincipalName( + PrincipalName.TGS_DEFAULT_SRV_NAME, + PrincipalName.KRB_NT_SRV_INST, + referral.getRealm()); + throw new KrbException(Krb5.KRB_ERR_WRONG_REALM); + } + } + } + EncryptionKey ckey = keyForUser(body.cname, eType, false); EncryptionKey skey = keyForUser(service, eType, true); @@ -936,8 +1127,12 @@ public class KDC { // Session key EncryptionKey key = generateRandomKey(eType); // Check time, TODO + KerberosTime from = body.from; KerberosTime till = body.till; KerberosTime rtime = body.rtime; + if (from == null || from.isZero()) { + from = timeAfter(0); + } if (till == null) { throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO } else if (till.isZero()) { @@ -963,7 +1158,8 @@ public class KDC { if (body.kdcOptions.get(KDCOptions.FORWARDABLE)) { List sensitives = (List) options.get(Option.SENSITIVE_ACCOUNTS); - if (sensitives != null && sensitives.contains(body.cname.toString())) { + if (sensitives != null + && sensitives.contains(body.cname.toString())) { // Cannot make FORWARDABLE } else { bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; @@ -971,7 +1167,7 @@ public class KDC { } if (body.kdcOptions.get(KDCOptions.RENEWABLE)) { bFlags[Krb5.TKT_OPTS_RENEWABLE] = true; - //renew = new KerberosTime(new Date().getTime() + 1000 * 3600 * 24 * 7); + //renew = timeAfter(3600 * 24 * 7); } if (body.kdcOptions.get(KDCOptions.PROXIABLE)) { bFlags[Krb5.TKT_OPTS_PROXIABLE] = true; @@ -993,7 +1189,8 @@ public class KDC { pas2 = new DerValue[] { new DerValue(new ETypeInfo2(1, null, null).asn1Encode()), new DerValue(new ETypeInfo2(1, "", null).asn1Encode()), - new DerValue(new ETypeInfo2(1, realm, new byte[]{1}).asn1Encode()), + new DerValue(new ETypeInfo2( + 1, realm, new byte[]{1}).asn1Encode()), }; pas = new DerValue[] { new DerValue(new ETypeInfo(1, null).asn1Encode()), @@ -1003,7 +1200,8 @@ public class KDC { break; case 2: // we still reject non-null s2kparams and prefer E2 over E pas2 = new DerValue[] { - new DerValue(new ETypeInfo2(1, realm, new byte[]{1}).asn1Encode()), + new DerValue(new ETypeInfo2( + 1, realm, new byte[]{1}).asn1Encode()), new DerValue(new ETypeInfo2(1, null, null).asn1Encode()), new DerValue(new ETypeInfo2(1, "", null).asn1Encode()), }; @@ -1054,7 +1252,7 @@ public class KDC { epas[i], epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ? null : getSalt(body.cname), - null).asn1Encode()); + getParams(body.cname, epas[i])).asn1Encode()); } boolean allOld = true; for (int i: eTypes) { @@ -1088,21 +1286,47 @@ public class KDC { outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray())); } - PAData[] inPAs = KDCReqDotPAData(asReq); - if (inPAs == null || inPAs.length == 0) { + PAData[] inPAs = asReq.pAData; + List enc_outPAs = new ArrayList<>(); + + byte[] paEncTimestamp = null; + if (inPAs != null) { + for (PAData inPA : inPAs) { + if (inPA.getType() == Krb5.PA_ENC_TIMESTAMP) { + paEncTimestamp = inPA.getValue(); + } + } + } + + if (paEncTimestamp == null) { Object preauth = options.get(Option.PREAUTH_REQUIRED); if (preauth == null || preauth.equals(Boolean.TRUE)) { throw new KrbException(Krb5.KDC_ERR_PREAUTH_REQUIRED); } } else { + EncryptionKey pakey = null; try { - EncryptedData data = newEncryptedData(new DerValue(inPAs[0].getValue())); - EncryptionKey pakey = keyForUser(body.cname, data.getEType(), false); + EncryptedData data = newEncryptedData( + new DerValue(paEncTimestamp)); + pakey = keyForUser(body.cname, data.getEType(), false); data.decrypt(pakey, KeyUsage.KU_PA_ENC_TS); } catch (Exception e) { - throw new KrbException(Krb5.KDC_ERR_PREAUTH_FAILED); + KrbException ke = new KrbException(Krb5.KDC_ERR_PREAUTH_FAILED); + ke.initCause(e); + throw ke; } bFlags[Krb5.TKT_OPTS_PRE_AUTHENT] = true; + for (PAData pa : inPAs) { + if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { + Checksum ckSum = new Checksum( + Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128, + asReqbytes, ckey, KeyUsage.KU_AS_REQ); + enc_outPAs.add(new PAData(Krb5.PA_REQ_ENC_PA_REP, + ckSum.asn1Encode())); + bFlags[Krb5.TKT_OPTS_ENC_PA_REP] = true; + break; + } + } } TicketFlags tFlags = new TicketFlags(bFlags); @@ -1111,8 +1335,8 @@ public class KDC { key, body.cname, new TransitedEncoding(1, new byte[0]), - new KerberosTime(new Date()), - body.from, + timeAfter(0), + from, till, rtime, body.addresses, null); @@ -1123,19 +1347,21 @@ public class KDC { EncASRepPart enc_part = new EncASRepPart( key, new LastReq(new LastReqEntry[]{ - new LastReqEntry(0, new KerberosTime(new Date().getTime() - 10000)) + new LastReqEntry(0, timeAfter(-10)) }), body.getNonce(), // TODO: detect replay? - new KerberosTime(new Date().getTime() + 1000 * 3600 * 24), + timeAfter(3600 * 24), // Next 5 and last MUST be same with ticket tFlags, - new KerberosTime(new Date()), - body.from, + timeAfter(0), + from, till, rtime, service, - body.addresses + body.addresses, + enc_outPAs.toArray(new PAData[enc_outPAs.size()]) ); - EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_AS_REP_PART); + EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), + KeyUsage.KU_ENC_AS_REP_PART); ASRep asRep = new ASRep( outPAs.toArray(new PAData[outPAs.size()]), body.cname, @@ -1180,8 +1406,10 @@ public class KDC { if (kerr == null) { if (ke.returnCode() == Krb5.KDC_ERR_PREAUTH_REQUIRED || ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) { + outPAs.add(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0])); + } + if (outPAs.size() > 0) { DerOutputStream bytes = new DerOutputStream(); - bytes.write(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0]).asn1Encode()); for (PAData p: outPAs) { bytes.write(p.asn1Encode()); } @@ -1190,7 +1418,7 @@ public class KDC { eData = temp.toByteArray(); } kerr = new KRBError(null, null, null, - new KerberosTime(new Date()), + timeAfter(0), 0, ke.returnCode(), body.cname, @@ -1268,6 +1496,35 @@ public class KDC { throw new KrbException("Illegal duration format " + s); } + private int[] filterSupported(int[] input) { + int count = 0; + for (int i = 0; i < input.length; i++) { + if (!EType.isSupported(input[i])) { + continue; + } + if (SUPPORTED_ETYPES != null) { + boolean supported = false; + for (String se : SUPPORTED_ETYPES.split(",")) { + if (Config.getType(se) == input[i]) { + supported = true; + break; + } + } + if (!supported) { + continue; + } + } + if (count != i) { + input[count] = input[i]; + } + count++; + } + if (count != input.length) { + input = Arrays.copyOf(input, count); + } + return input; + } + /** * Generates a line for a KDC to put inside [realms] of krb5.conf * @return REALM.NAME = { kdc = host:port etc } @@ -1292,6 +1549,20 @@ public class KDC { * @throws java.io.IOException for any communication error */ protected void startServer(int port, boolean asDaemon) throws IOException { + if (nativeKdc != null) { + startNativeServer(port, asDaemon); + } else { + startJavaServer(port, asDaemon); + } + } + + private void startNativeServer(int port, boolean asDaemon) throws IOException { + nativeKdc.prepare(); + nativeKdc.init(); + kdcProc = nativeKdc.kdc(); + } + + private void startJavaServer(int port, boolean asDaemon) throws IOException { if (port > 0) { u1 = new DatagramSocket(port, InetAddress.getByName("127.0.0.1")); t1 = new ServerSocket(port); @@ -1384,19 +1655,37 @@ public class KDC { } } + public void kinit(String user, String ccache) throws Exception { + if (user.indexOf('@') < 0) { + user = user + "@" + realm; + } + if (nativeKdc != null) { + nativeKdc.kinit(user, ccache); + } else { + Context.fromUserPass(user, passwords.get(user), false) + .ccache(ccache); + } + } + boolean isReady() { return udpConsumerReady && tcpConsumerReady && dispatcherReady; } public void terminate() { - try { - thread1.stop(); - thread2.stop(); - thread3.stop(); - u1.close(); - t1.close(); - } catch (Exception e) { - // OK + if (nativeKdc != null) { + System.out.println("Killing kdc..."); + kdcProc.destroyForcibly(); + System.out.println("Done"); + } else { + try { + thread1.stop(); + thread2.stop(); + thread3.stop(); + u1.close(); + t1.close(); + } catch (Exception e) { + // OK + } } } @@ -1551,8 +1840,270 @@ public class KDC { } } + /** + * A native KDC using the binaries in nativePath. Attention: + * this is using binaries, not an existing KDC instance. + * An implementation of this takes care of configuration, + * principal db managing and KDC startup. + */ + static abstract class NativeKdc { + + protected Map env; + protected String nativePath; + protected String base; + protected String realm; + protected int port; + + NativeKdc(String nativePath, KDC kdc) { + if (kdc.port == 0) { + kdc.port = 8000 + new java.util.Random().nextInt(10000); + } + this.nativePath = nativePath; + this.realm = kdc.realm; + this.port = kdc.port; + this.base = Paths.get("" + port).toAbsolutePath().toString(); + } + + // Add a new principal + abstract void addPrincipal(String user, String pass); + // Add a keytab entry + abstract void ktadd(String user, String ktab); + // Initialize KDC + abstract void init(); + // Start kdc + abstract Process kdc(); + // Configuration + abstract void prepare(); + // Fill ccache + abstract void kinit(String user, String ccache); + + static NativeKdc get(KDC kdc) { + String prop = System.getProperty("native.kdc.path"); + if (prop == null) { + return null; + } else if (Files.exists(Paths.get(prop, "sbin/krb5kdc"))) { + return new MIT(true, prop, kdc); + } else if (Files.exists(Paths.get(prop, "kdc/krb5kdc"))) { + return new MIT(false, prop, kdc); + } else if (Files.exists(Paths.get(prop, "libexec/kdc"))) { + return new Heimdal(prop, kdc); + } else { + throw new IllegalArgumentException("Strange " + prop); + } + } + + Process run(boolean wait, String... cmd) { + try { + System.out.println("Running " + cmd2str(env, cmd)); + ProcessBuilder pb = new ProcessBuilder(); + pb.inheritIO(); + pb.environment().putAll(env); + Process p = pb.command(cmd).start(); + if (wait) { + if (p.waitFor() < 0) { + throw new RuntimeException("exit code is not null"); + } + return null; + } else { + return p; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private String cmd2str(Map env, String... cmd) { + return env.entrySet().stream().map(e -> e.getKey()+"="+e.getValue()) + .collect(Collectors.joining(" ")) + " " + + Stream.of(cmd).collect(Collectors.joining(" ")); + } + } + + // Heimdal KDC. Build your own and run "make install" to nativePath. + static class Heimdal extends NativeKdc { + + Heimdal(String nativePath, KDC kdc) { + super(nativePath, kdc); + Map environment = new HashMap<>(); + environment.put("KRB5_CONFIG", base + "/krb5.conf"); + environment.put("KRB5_TRACE", "/dev/stderr"); + environment.put("DYLD_LIBRARY_PATH", nativePath + "/lib"); + environment.put("LD_LIBRARY_PATH", nativePath + "/lib"); + this.env = Collections.unmodifiableMap(environment); + } + + @Override + public void addPrincipal(String user, String pass) { + run(true, nativePath + "/bin/kadmin", "-l", "-r", realm, + "add", "-p", pass, "--use-defaults", user); + } + + @Override + public void ktadd(String user, String ktab) { + run(true, nativePath + "/bin/kadmin", "-l", "-r", realm, + "ext_keytab", "-k", ktab, user); + } + + @Override + public void init() { + run(true, nativePath + "/bin/kadmin", "-l", "-r", realm, + "init", "--realm-max-ticket-life=1day", + "--realm-max-renewable-life=1month", realm); + } + + @Override + public Process kdc() { + return run(false, nativePath + "/libexec/kdc", + "--addresses=127.0.0.1", "-P", "" + port); + } + + @Override + public void prepare() { + try { + Files.createDirectory(Paths.get(base)); + Files.write(Paths.get(base + "/krb5.conf"), Arrays.asList( + "[libdefaults]", + "default_realm = " + realm, + "default_keytab_name = FILE:" + base + "/krb5.keytab", + "forwardable = true", + "dns_lookup_kdc = no", + "dns_lookup_realm = no", + "dns_canonicalize_hostname = false", + "\n[realms]", + realm + " = {", + " kdc = localhost:" + port, + "}", + "\n[kdc]", + "db-dir = " + base, + "database = {", + " label = {", + " dbname = " + base + "/current-db", + " realm = " + realm, + " mkey_file = " + base + "/mkey.file", + " acl_file = " + base + "/heimdal.acl", + " log_file = " + base + "/current.log", + " }", + "}", + SUPPORTED_ETYPES == null ? "" + : ("\n[kadmin]\ndefault_keys = " + + (SUPPORTED_ETYPES + ",") + .replaceAll(",", ":pw-salt ")), + "\n[logging]", + "kdc = 0-/FILE:" + base + "/messages.log", + "krb5 = 0-/FILE:" + base + "/messages.log", + "default = 0-/FILE:" + base + "/messages.log" + )); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + void kinit(String user, String ccache) { + String tmpName = base + "/" + user + "." + + System.identityHashCode(this) + ".keytab"; + ktadd(user, tmpName); + run(true, nativePath + "/bin/kinit", + "-f", "-t", tmpName, "-c", ccache, user); + } + } + + // MIT krb5 KDC. Make your own exploded (install == false), or + // "make install" into nativePath (install == true). + static class MIT extends NativeKdc { + + private boolean install; // "make install" or "make" + + MIT(boolean install, String nativePath, KDC kdc) { + super(nativePath, kdc); + this.install = install; + Map environment = new HashMap<>(); + environment.put("KRB5_KDC_PROFILE", base + "/kdc.conf"); + environment.put("KRB5_CONFIG", base + "/krb5.conf"); + environment.put("KRB5_TRACE", "/dev/stderr"); + environment.put("DYLD_LIBRARY_PATH", nativePath + "/lib"); + environment.put("LD_LIBRARY_PATH", nativePath + "/lib"); + this.env = Collections.unmodifiableMap(environment); + } + + @Override + public void addPrincipal(String user, String pass) { + run(true, nativePath + + (install ? "/sbin/" : "/kadmin/cli/") + "kadmin.local", + "-q", "addprinc -pw " + pass + " " + user); + } + + @Override + public void ktadd(String user, String ktab) { + run(true, nativePath + + (install ? "/sbin/" : "/kadmin/cli/") + "kadmin.local", + "-q", "ktadd -k " + ktab + " -norandkey " + user); + } + + @Override + public void init() { + run(true, nativePath + + (install ? "/sbin/" : "/kadmin/dbutil/") + "kdb5_util", + "create", "-s", "-W", "-P", "olala"); + } + + @Override + public Process kdc() { + return run(false, nativePath + + (install ? "/sbin/" : "/kdc/") + "krb5kdc", + "-n"); + } + + @Override + public void prepare() { + try { + Files.createDirectory(Paths.get(base)); + Files.write(Paths.get(base + "/kdc.conf"), Arrays.asList( + "[kdcdefaults]", + "\n[realms]", + realm + "= {", + " kdc_listen = " + this.port, + " kdc_tcp_listen = " + this.port, + " database_name = " + base + "/principal", + " key_stash_file = " + base + "/.k5.ATHENA.MIT.EDU", + SUPPORTED_ETYPES == null ? "" + : (" supported_enctypes = " + + (SUPPORTED_ETYPES + ",") + .replaceAll(",", ":normal ")), + "}" + )); + Files.write(Paths.get(base + "/krb5.conf"), Arrays.asList( + "[libdefaults]", + "default_realm = " + realm, + "default_keytab_name = FILE:" + base + "/krb5.keytab", + "forwardable = true", + "dns_lookup_kdc = no", + "dns_lookup_realm = no", + "dns_canonicalize_hostname = false", + "\n[realms]", + realm + " = {", + " kdc = localhost:" + port, + "}", + "\n[logging]", + "kdc = FILE:" + base + "/krb5kdc.log" + )); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + void kinit(String user, String ccache) { + String tmpName = base + "/" + user + "." + + System.identityHashCode(this) + ".keytab"; + ktadd(user, tmpName); + run(true, nativePath + + (install ? "/bin/" : "/clients/kinit/") + "kinit", + "-f", "-t", tmpName, "-c", ccache, user); + } + } + // Calling private methods thru reflections - private static final Field getPADataField; private static final Field getEType; private static final Constructor ctorEncryptedData; private static final Method stringToKey; @@ -1562,8 +2113,6 @@ public class KDC { try { ctorEncryptedData = EncryptedData.class.getDeclaredConstructor(DerValue.class); ctorEncryptedData.setAccessible(true); - getPADataField = KDCReq.class.getDeclaredField("pAData"); - getPADataField.setAccessible(true); getEType = KDCReqBody.class.getDeclaredField("eType"); getEType.setAccessible(true); stringToKey = EncryptionKey.class.getDeclaredMethod( @@ -1585,13 +2134,6 @@ public class KDC { throw new AssertionError(e); } } - private static PAData[] KDCReqDotPAData(KDCReq req) { - try { - return (PAData[])getPADataField.get(req); - } catch (Exception e) { - throw new AssertionError(e); - } - } private static int[] KDCReqBodyDotEType(KDCReqBody body) { try { return (int[]) getEType.get(body); diff --git a/test/sun/security/krb5/auto/LifeTimeInSeconds.java b/test/sun/security/krb5/auto/LifeTimeInSeconds.java index 9d4c6d7b017f44607e6de1794c62820e95773660..23c953183ba3c07671ed6354df593155484a95c8 100644 --- a/test/sun/security/krb5/auto/LifeTimeInSeconds.java +++ b/test/sun/security/krb5/auto/LifeTimeInSeconds.java @@ -40,7 +40,7 @@ public class LifeTimeInSeconds { int time = cred.getRemainingLifetime(); int time2 = cred.getRemainingInitLifetime(null); // The test KDC issues a TGT with a default lifetime of 11 hours - int elevenhrs = 11*3600; + int elevenhrs = KDC.DEFAULT_LIFETIME; if (time > elevenhrs+60 || time < elevenhrs-60) { throw new Exception("getRemainingLifetime returns wrong value."); } diff --git a/test/sun/security/krb5/auto/NullRenewUntil.java b/test/sun/security/krb5/auto/NullRenewUntil.java new file mode 100644 index 0000000000000000000000000000000000000000..2f7d4a4efbeb4439a98bda5fc2b694b8b416f91e --- /dev/null +++ b/test/sun/security/krb5/auto/NullRenewUntil.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017, 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 8186576 + * @summary KerberosTicket does not properly handle renewable tickets + * at the end of their lifetime + * @library /lib/testlibrary/ + * @compile -XDignore.symbol.file NullRenewUntil.java + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock -Dtest.set.null.renew NullRenewUntil + */ + +import jdk.testlibrary.Asserts; +import sun.security.krb5.Config; + +import javax.security.auth.kerberos.KerberosTicket; + +public class NullRenewUntil { + + public static void main(String[] args) throws Exception { + + OneKDC kdc = new OneKDC(null); + + KDC.saveConfig(OneKDC.KRB5_CONF, kdc, + "ticket_lifetime = 10s", + "renew_lifetime = 11s"); + Config.refresh(); + + KerberosTicket ticket = Context + .fromUserPass(OneKDC.USER, OneKDC.PASS, false).s() + .getPrivateCredentials(KerberosTicket.class).iterator().next(); + + System.out.println(ticket); + Asserts.assertTrue(ticket.getRenewTill() != null, ticket.toString()); + + Thread.sleep(2000); + + ticket.refresh(); + System.out.println(ticket); + Asserts.assertTrue(ticket.getRenewTill() == null, ticket.toString()); + + Thread.sleep(2000); + ticket.refresh(); + System.out.println(ticket); + } +} diff --git a/test/sun/security/krb5/auto/ReferralsTest.java b/test/sun/security/krb5/auto/ReferralsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..32e56344f67fbfabbe6385175d0c3ad489f45d7b --- /dev/null +++ b/test/sun/security/krb5/auto/ReferralsTest.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. + * 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 8215032 + * @run main/othervm/timeout=120 -Dsun.security.krb5.debug=true ReferralsTest + * @summary Test Kerberos cross-realm referrals (RFC 6806) + */ + +import java.io.File; +import java.security.Principal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.security.auth.kerberos.KerberosTicket; +import javax.security.auth.Subject; + +import org.ietf.jgss.GSSName; + +import sun.security.jgss.GSSUtil; +import sun.security.krb5.PrincipalName; + +public class ReferralsTest { + private static final boolean DEBUG = true; + private static final String krbConfigName = "krb5-localkdc.conf"; + private static final String realmKDC1 = "RABBIT.HOLE"; + private static final String realmKDC2 = "DEV.RABBIT.HOLE"; + private static final char[] password = "123qwe@Z".toCharArray(); + + // Names + private static final String clientName = "test"; + private static final String serviceName = "http" + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + + "server.dev.rabbit.hole"; + + // Alias + private static final String clientAlias = clientName + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1; + + // Names + realms + private static final String clientKDC1Name = clientAlias.replaceAll( + PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" + + PrincipalName.NAME_REALM_SEPARATOR_STR) + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1; + private static final String clientKDC2Name = clientName + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2; + private static final String serviceKDC2Name = serviceName + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2; + + public static void main(String[] args) throws Exception { + try { + initializeKDCs(); + testSubjectCredentials(); + testDelegated(); + } finally { + cleanup(); + } + } + + private static void initializeKDCs() throws Exception { + KDC kdc1 = KDC.create(realmKDC1, "localhost", 0, true); + kdc1.addPrincipalRandKey(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC1); + kdc1.addPrincipal(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC1 + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2, + password); + kdc1.addPrincipal(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC2, + password); + + KDC kdc2 = KDC.create(realmKDC2, "localhost", 0, true); + kdc2.addPrincipalRandKey(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC2); + kdc2.addPrincipal(clientKDC2Name, password); + kdc2.addPrincipal(serviceName, password); + kdc2.addPrincipal(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC1, + password); + kdc2.addPrincipal(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC2 + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, + password); + + kdc1.registerAlias(clientAlias, kdc2); + kdc1.registerAlias(serviceName, kdc2); + kdc2.registerAlias(clientAlias, clientKDC2Name); + + Map> mapKDC2 = new HashMap<>(); + mapKDC2.put(serviceName + "@" + realmKDC2, Arrays.asList( + new String[]{serviceName + "@" + realmKDC2})); + kdc2.setOption(KDC.Option.ALLOW_S4U2PROXY, mapKDC2); + + KDC.saveConfig(krbConfigName, kdc1, kdc2, + "forwardable=true"); + System.setProperty("java.security.krb5.conf", krbConfigName); + } + + private static void cleanup() { + File f = new File(krbConfigName); + if (f.exists()) { + f.delete(); + } + } + + /* + * The client subject (whose principal is + * test@RABBIT.HOLE@RABBIT.HOLE) will obtain a TGT after + * realm referral and name canonicalization (TGT cname + * will be test@DEV.RABBIT.HOLE). With this TGT, the client will request + * a TGS for service http/server.dev.rabbit.hole@RABBIT.HOLE. After + * realm referral, a http/server.dev.rabbit.hole@DEV.RABBIT.HOLE TGS + * will be obtained. + * + * Assert that we get the proper TGT and TGS tickets, and that they are + * associated to the client subject. + * + * Assert that if we request a TGS for the same service again (based on the + * original service name), we don't get a new one but the previous, + * already in the subject credentials. + */ + private static void testSubjectCredentials() throws Exception { + Subject clientSubject = new Subject(); + Context clientContext = Context.fromUserPass(clientSubject, + clientKDC1Name, password, false); + + Set clientPrincipals = clientSubject.getPrincipals(); + if (clientPrincipals.size() != 1) { + throw new Exception("Only one client subject principal expected"); + } + Principal clientPrincipal = clientPrincipals.iterator().next(); + if (DEBUG) { + System.out.println("Client subject principal: " + + clientPrincipal.getName()); + } + if (!clientPrincipal.getName().equals(clientKDC1Name)) { + throw new Exception("Unexpected client subject principal."); + } + + clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); + clientContext.take(new byte[0]); + Set clientTickets = + clientSubject.getPrivateCredentials(KerberosTicket.class); + boolean tgtFound = false; + boolean tgsFound = false; + for (KerberosTicket clientTicket : clientTickets) { + String cname = clientTicket.getClient().getName(); + String sname = clientTicket.getServer().getName(); + if (cname.equals(clientKDC2Name)) { + if (sname.equals(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + + realmKDC2 + PrincipalName.NAME_REALM_SEPARATOR_STR + + realmKDC2)) { + tgtFound = true; + } else if (sname.equals(serviceKDC2Name)) { + tgsFound = true; + } + } + if (DEBUG) { + System.out.println("Client subject KerberosTicket:"); + System.out.println(clientTicket); + } + } + if (!tgtFound || !tgsFound) { + throw new Exception("client subject tickets (TGT/TGS) not found."); + } + int numOfTickets = clientTickets.size(); + clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); + clientContext.take(new byte[0]); + clientContext.status(); + int newNumOfTickets = + clientSubject.getPrivateCredentials(KerberosTicket.class).size(); + if (DEBUG) { + System.out.println("client subject number of tickets: " + + numOfTickets); + System.out.println("client subject new number of tickets: " + + newNumOfTickets); + } + if (numOfTickets != newNumOfTickets) { + throw new Exception("Useless client subject TGS request because" + + " TGS was not found in private credentials."); + } + } + + /* + * The server (http/server.dev.rabbit.hole@DEV.RABBIT.HOLE) + * will authenticate on itself on behalf of the client + * (test@DEV.RABBIT.HOLE). Cross-realm referrals will occur + * when requesting different TGTs and TGSs (including the + * request for delegated credentials). + */ + private static void testDelegated() throws Exception { + Context c = Context.fromUserPass(clientKDC2Name, + password, false); + c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); + Context s = Context.fromUserPass(serviceKDC2Name, + password, true); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + Context delegatedContext = s.delegated(); + delegatedContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID); + delegatedContext.x().requestMutualAuth(false); + Context s2 = Context.fromUserPass(serviceKDC2Name, + password, true); + s2.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + + // Test authentication + Context.handshake(delegatedContext, s2); + if (!delegatedContext.x().isEstablished() || !s2.x().isEstablished()) { + throw new Exception("Delegated authentication failed"); + } + + // Test identities + GSSName contextInitiatorName = delegatedContext.x().getSrcName(); + GSSName contextAcceptorName = delegatedContext.x().getTargName(); + if (DEBUG) { + System.out.println("Context initiator: " + contextInitiatorName); + System.out.println("Context acceptor: " + contextAcceptorName); + } + if (!contextInitiatorName.toString().equals(clientKDC2Name) || + !contextAcceptorName.toString().equals(serviceName)) { + throw new Exception("Unexpected initiator or acceptor names"); + } + } +} diff --git a/test/sun/security/krb5/auto/Renew.java b/test/sun/security/krb5/auto/Renew.java new file mode 100644 index 0000000000000000000000000000000000000000..fdfb488aad07f79c9f8801d13460b03c11ec8eda --- /dev/null +++ b/test/sun/security/krb5/auto/Renew.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, 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 8058290 + * @summary JAAS Krb5LoginModule has suspect ticket-renewal logic, + * relies on clockskew grace + * @compile -XDignore.symbol.file Renew.java + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock Renew 1 + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock Renew 2 + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock Renew 3 + */ + +import sun.security.krb5.Config; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Date; +import javax.security.auth.kerberos.KerberosTicket; + +public class Renew { + + public static void main(String[] args) throws Exception { + + // Three test cases: + // 1. renewTGT=false + // 2. renewTGT=true with a short life time, renew will happen + // 3. renewTGT=true with a long life time, renew won't happen + int test = Integer.parseInt(args[0]); + + OneKDC k = new OneKDC(null); + KDC.saveConfig(OneKDC.KRB5_CONF, k, + "renew_lifetime = 1d", + "ticket_lifetime = " + (test == 2? "10s": "8h")); + Config.refresh(); + k.writeJAASConf(); + + // KDC would save ccache in a file + System.setProperty("test.kdc.save.ccache", "cache.here"); + + Files.write(Paths.get(OneKDC.JAAS_CONF), Arrays.asList( + "first {", + " com.sun.security.auth.module.Krb5LoginModule required;", + "};", + "second {", + " com.sun.security.auth.module.Krb5LoginModule required", + " doNotPrompt=true", + " renewTGT=" + (test != 1), + " useTicketCache=true", + " ticketCache=cache.here;", + "};" + )); + + Context c; + + // The first login uses username and password + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + Date d1 = c.s().getPrivateCredentials(KerberosTicket.class).iterator().next().getAuthTime(); + + // 6s is longer than half of 10s + Thread.sleep(6000); + + // The second login uses the cache + c = Context.fromJAAS("second"); + Date d2 = c.s().getPrivateCredentials(KerberosTicket.class).iterator().next().getAuthTime(); + + if (test == 2) { + if (d1.equals(d2)) { + throw new Exception("Ticket not renewed"); + } + } else { + if (!d1.equals(d2)) { + throw new Exception("Ticket renewed"); + } + } + } +} diff --git a/test/sun/security/krb5/auto/Renewal.java b/test/sun/security/krb5/auto/Renewal.java new file mode 100644 index 0000000000000000000000000000000000000000..38639c761052dc241d2cc6e60af9ac860bc0fba0 --- /dev/null +++ b/test/sun/security/krb5/auto/Renewal.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2012, 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 8044500 + * @summary Add kinit options and krb5.conf flags that allow users to + * obtain renewable tickets and specify ticket lifetimes + * @library ../../../../java/security/testlibrary/ + * @compile -XDignore.symbol.file Renewal.java + * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock Renewal + */ + +import sun.security.jgss.GSSUtil; +import sun.security.krb5.Config; +import sun.security.krb5.internal.ccache.Credentials; +import sun.security.krb5.internal.ccache.FileCredentialsCache; + +import javax.security.auth.kerberos.KerberosTicket; +import java.util.Date; +import java.util.Random; +import java.util.Set; + +// The basic krb5 test skeleton you can copy from +public class Renewal { + + static OneKDC kdc; + static String clazz = "sun.security.krb5.internal.tools.Kinit"; + + public static void main(String[] args) throws Exception { + + kdc = new OneKDC(null); + kdc.writeJAASConf(); + kdc.setOption(KDC.Option.PREAUTH_REQUIRED, false); + + checkLogin(null, null, KDC.DEFAULT_LIFETIME, -1); + checkLogin("1h", null, 3600, -1); + checkLogin(null, "2d", KDC.DEFAULT_LIFETIME, 86400*2); + checkLogin("1h", "10h", 3600, 36000); + // When rtime is before till, use till as rtime + checkLogin("10h", "1h", 36000, 36000); + + try { + Class.forName(clazz); + } catch (ClassNotFoundException cnfe) { + return; + } + + checkKinit(null, null, null, null, KDC.DEFAULT_LIFETIME, -1); + checkKinit("1h", "10h", null, null, 3600, 36000); + checkKinit(null, null, "30m", "5h", 1800, 18000); + checkKinit("1h", "10h", "30m", "5h", 1800, 18000); + + checkKinitRenew(); + } + + static int count = 0; + + static void checkKinit( + String s1, // ticket_lifetime in krb5.conf, null if none + String s2, // renew_lifetime in krb5.conf, null if none + String c1, // -l on kinit, null if none + String c2, // -r on kinit, null if none + int t1, int t2 // expected lifetimes, -1 of unexpected + ) throws Exception { + KDC.saveConfig(OneKDC.KRB5_CONF, kdc, + s1 != null ? ("ticket_lifetime = " + s1) : "", + s2 != null ? ("renew_lifetime = " + s2) : ""); + Proc p = Proc.create(clazz); + if (c1 != null) { + p.args("-l", c1); + } + if (c2 != null) { + p.args("-r", c2); + } + count++; + p.args(OneKDC.USER, new String(OneKDC.PASS)) + .inheritIO() + .prop("sun.net.spi.nameservice.provider.1", "ns,mock") + .prop("java.security.krb5.conf", OneKDC.KRB5_CONF) + .env("KRB5CCNAME", "ccache" + count) + .start(); + if (p.waitFor() != 0) { + throw new Exception(); + } + FileCredentialsCache fcc = + FileCredentialsCache.acquireInstance(null, "ccache" + count); + Credentials cred = fcc.getDefaultCreds(); + checkRough(cred.getEndTime().toDate(), t1); + if (cred.getRenewTill() == null) { + checkRough(null, t2); + } else { + checkRough(cred.getRenewTill().toDate(), t2); + } + } + + static void checkKinitRenew() throws Exception { + Proc p = Proc.create(clazz) + .args("-R") + .inheritIO() + .prop("sun.net.spi.nameservice.provider.1", "ns,mock") + .prop("java.security.krb5.conf", OneKDC.KRB5_CONF) + .env("KRB5CCNAME", "ccache" + count) + .start(); + if (p.waitFor() != 0) { + throw new Exception(); + } + } + + static void checkLogin( + String s1, // ticket_lifetime in krb5.conf, null if none + String s2, // renew_lifetime in krb5.conf, null if none + int t1, int t2 // expected lifetimes, -1 of unexpected + ) throws Exception { + KDC.saveConfig(OneKDC.KRB5_CONF, kdc, + s1 != null ? ("ticket_lifetime = " + s1) : "", + s2 != null ? ("renew_lifetime = " + s2) : ""); + Config.refresh(); + + Context c; + c = Context.fromJAAS("client"); + + Set tickets = + c.s().getPrivateCredentials(KerberosTicket.class); + if (tickets.size() != 1) { + throw new Exception(); + } + KerberosTicket ticket = tickets.iterator().next(); + + checkRough(ticket.getEndTime(), t1); + checkRough(ticket.getRenewTill(), t2); + } + + static void checkRough(Date t, int duration) throws Exception { + Date now = new Date(); + if (t == null && duration == -1) { + return; + } + long change = (t.getTime() - System.currentTimeMillis()) / 1000; + if (change > duration + 20 || change < duration - 20) { + throw new Exception(t + " is not " + duration); + } + } +} diff --git a/test/sun/security/krb5/auto/SaslGSS.java b/test/sun/security/krb5/auto/SaslGSS.java deleted file mode 100644 index d21cfebb19bd63d3892921757ec56ac0d56ef94b..0000000000000000000000000000000000000000 --- a/test/sun/security/krb5/auto/SaslGSS.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2013, 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 8012082 8019267 - * @summary SASL: auth-conf negotiated, but unencrypted data is accepted, - * reset to unencrypt - * @compile -XDignore.symbol.file SaslGSS.java - * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock SaslGSS - */ - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.RealmCallback; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslServer; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.HashMap; -import java.util.Locale; -import java.util.logging.ConsoleHandler; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.ietf.jgss.*; -import sun.security.jgss.GSSUtil; - -public class SaslGSS { - - public static void main(String[] args) throws Exception { - - String name = "host." + OneKDC.REALM.toLowerCase(Locale.US); - - new OneKDC(null).writeJAASConf(); - System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); - - // Client in JGSS so that it can control wrap privacy mode - GSSManager m = GSSManager.getInstance(); - GSSContext sc = m.createContext( - m.createName(OneKDC.SERVER, GSSUtil.NT_GSS_KRB5_PRINCIPAL), - GSSUtil.GSS_KRB5_MECH_OID, - null, - GSSContext.DEFAULT_LIFETIME); - sc.requestMutualAuth(false); - - // Server in SASL - final HashMap props = new HashMap(); - props.put(Sasl.QOP, "auth-conf"); - SaslServer ss = Sasl.createSaslServer("GSSAPI", "server", - name, props, - new CallbackHandler() { - public void handle(Callback[] callbacks) - throws IOException, UnsupportedCallbackException { - for (Callback cb : callbacks) { - if (cb instanceof RealmCallback) { - ((RealmCallback) cb).setText(OneKDC.REALM); - } else if (cb instanceof AuthorizeCallback) { - ((AuthorizeCallback) cb).setAuthorized(true); - } - } - } - }); - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - PrintStream oldErr = System.err; - System.setErr(new PrintStream(bout)); - - Logger.getLogger("javax.security.sasl").setLevel(Level.ALL); - Handler h = new ConsoleHandler(); - h.setLevel(Level.ALL); - Logger.getLogger("javax.security.sasl").addHandler(h); - - byte[] token = new byte[0]; - - try { - // Handshake - token = sc.initSecContext(token, 0, token.length); - token = ss.evaluateResponse(token); - token = sc.unwrap(token, 0, token.length, new MessageProp(0, false)); - token[0] = (byte)(((token[0] & 4) != 0) ? 4 : 2); - token = sc.wrap(token, 0, token.length, new MessageProp(0, false)); - ss.evaluateResponse(token); - } finally { - System.setErr(oldErr); - } - - // Talk - // 1. Client sends a auth-int message - byte[] hello = "hello".getBytes(); - MessageProp qop = new MessageProp(0, false); - token = sc.wrap(hello, 0, hello.length, qop); - // 2. Server accepts it anyway - ss.unwrap(token, 0, token.length); - // 3. Server sends a message - token = ss.wrap(hello, 0, hello.length); - // 4. Client accepts, should be auth-conf - sc.unwrap(token, 0, token.length, qop); - if (!qop.getPrivacy()) { - throw new Exception(); - } - - for (String s: bout.toString().split("\\n")) { - if (s.contains("KRB5SRV04") && s.contains("NULL")) { - return; - } - } - System.out.println("======================="); - System.out.println(bout.toString()); - System.out.println("======================="); - throw new Exception("Haven't seen KRB5SRV04 with NULL"); - } -} diff --git a/test/sun/security/krb5/config/Duration.java b/test/sun/security/krb5/config/Duration.java new file mode 100644 index 0000000000000000000000000000000000000000..d9c0f3961c780a6eeff0e269ce9f3fc1b983b32b --- /dev/null +++ b/test/sun/security/krb5/config/Duration.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014, 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 8044500 + * @summary Add kinit options and krb5.conf flags that allow users to + * obtain renewable tickets and specify ticket lifetimes + * @compile -XDignore.symbol.file Duration.java + * @run main Duration + */ +import sun.security.krb5.Config; +import sun.security.krb5.KrbException; + +public class Duration { + public static void main(String[] args) throws Exception { + check("123", 123); + check("1:1", 3660); + check("1:1:1", 3661); + check("1d", 86400); + check("1h", 3600); + check("1h1m", 3660); + check("1h 1m", 3660); + check("1d 1h 1m 1s", 90061); + check("1d1h1m1s", 90061); + + check("", -1); + check("abc", -1); + check("1ms", -1); + check("1d1d", -1); + check("1h1d", -1); + check("x1h", -1); + check("1h x 1m", -1); + check(":", -1); + check("1:60", -1); + check("1:1:1:1", -1); + check("1:1:1:", -1); + } + + static void check(String s, int ex) throws Exception { + System.out.print("\u001b[1;37;41m" +s + " " + ex); + System.out.print("\u001b[m\n"); + try { + int result = Config.duration(s); + if (result != ex) throw new Exception("for " + s + " is " + result); + } catch (KrbException ke) { + ke.printStackTrace(); + if (ex != -1) throw new Exception(); + } + } +} diff --git a/test/sun/security/provider/DSA/TestMaxLengthDER.java b/test/sun/security/provider/DSA/TestMaxLengthDER.java new file mode 100644 index 0000000000000000000000000000000000000000..a4f447c3c11db028ebdee4c6d3fdcca107af1115 --- /dev/null +++ b/test/sun/security/provider/DSA/TestMaxLengthDER.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2017, 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 8183591 + * @summary Test decoding of DER length fields containing Integer.MAX_VALUE + * @run main TestMaxLengthDER + */ + +import java.io.*; +import java.math.*; +import java.security.*; +import java.security.spec.*; + +public class TestMaxLengthDER { + + public static void main(String[] args) throws Exception { + + String message = "Message"; + Signature sig = Signature.getInstance("SHA256withDSA"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); + SecureRandom rnd = new SecureRandom(); + rnd.setSeed(1); + kpg.initialize(2048, rnd); + KeyPair kp = kpg.generateKeyPair(); + sig.initSign(kp.getPrivate()); + sig.update(message.getBytes()); + byte[] sigData = sig.sign(); + + // Set the length of the second integer to Integer.MAX_VALUE + // First copy all the signature data to the correct location + int lengthPos = sigData[3] + 5; + byte[] modifiedSigData = new byte[sigData.length + 4]; + System.arraycopy(sigData, 0, modifiedSigData, 0, lengthPos); + System.arraycopy(sigData, lengthPos + 1, modifiedSigData, + lengthPos + 5, sigData.length - (lengthPos + 1)); + + // Increase the length (in bytes) of the sequence to account for + // the larger length field + modifiedSigData[1] += 4; + + // Modify the length field + modifiedSigData[lengthPos] = (byte) 0x84; + modifiedSigData[lengthPos + 1] = (byte) 0x7F; + modifiedSigData[lengthPos + 2] = (byte) 0xFF; + modifiedSigData[lengthPos + 3] = (byte) 0xFF; + modifiedSigData[lengthPos + 4] = (byte) 0xFF; + + sig.initVerify(kp.getPublic()); + sig.update(message.getBytes()); + + try { + sig.verify(modifiedSigData); + throw new RuntimeException("No exception on misencoded signature"); + } catch (SignatureException ex) { + if (ex.getCause() instanceof EOFException) { + // this is expected + } else { + throw ex; + } + } + } +} diff --git a/test/sun/security/tools/jarsigner/EntriesOrder.java b/test/sun/security/tools/jarsigner/EntriesOrder.java index 96c90e98e12b20b19cf231de6e48b46189b154ca..908f6ef48be0598ca5dacbb6a49b461e770ead2f 100644 --- a/test/sun/security/tools/jarsigner/EntriesOrder.java +++ b/test/sun/security/tools/jarsigner/EntriesOrder.java @@ -25,6 +25,9 @@ * @test * @bug 8031572 * @summary jarsigner -verify exits with 0 when a jar file is not properly signed + * @library /lib/testlibrary + * @build jdk.testlibrary.IOUtils + * @run main EntriesOrder */ import java.io.FileInputStream; @@ -39,6 +42,8 @@ import java.util.jar.JarInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import jdk.testlibrary.IOUtils; + public class EntriesOrder { public static void main(String[] args) throws Exception { @@ -106,7 +111,7 @@ public class EntriesOrder { Enumeration jes = jf.entries(); while (jes.hasMoreElements()) { JarEntry je = jes.nextElement(); - sun.misc.IOUtils.readFully(jf.getInputStream(je), -1, true); + IOUtils.readFully(jf.getInputStream(je)); Certificate[] certs = je.getCertificates(); if (certs != null && certs.length > 0) { cc++; @@ -138,7 +143,7 @@ public class EntriesOrder { while (true) { JarEntry je = jis.getNextJarEntry(); if (je == null) break; - sun.misc.IOUtils.readFully(jis, -1, true); + IOUtils.readFully(jis); Certificate[] certs = je.getCertificates(); if (certs != null && certs.length > 0) { cc++; diff --git a/test/sun/security/tools/jarsigner/TimestampCheck.java b/test/sun/security/tools/jarsigner/TimestampCheck.java index b5070ce11fb25fb7bab1f7c4f60716ca663622b2..1018ace05f9c680a583e54ad99880b1a6d94c872 100644 --- a/test/sun/security/tools/jarsigner/TimestampCheck.java +++ b/test/sun/security/tools/jarsigner/TimestampCheck.java @@ -743,7 +743,7 @@ public class TimestampCheck { try (JarFile jf = new JarFile(file)) { JarEntry je = jf.getJarEntry("META-INF/SIGNER.RSA"); try (InputStream is = jf.getInputStream(je)) { - byte[] content = IOUtils.readFully(is, -1, true); + byte[] content = IOUtils.readAllBytes(is); PKCS7 p7 = new PKCS7(content); SignerInfo[] si = p7.getSignerInfos(); if (si == null || si.length == 0) { diff --git a/test/sun/security/tools/jarsigner/TsacertOptionTest.java b/test/sun/security/tools/jarsigner/TsacertOptionTest.java index 96116e1efde853f0759117812ae5ddc83b065b98..0bf70d35d244c4330a3fae88d8ad325ca18019b1 100644 --- a/test/sun/security/tools/jarsigner/TsacertOptionTest.java +++ b/test/sun/security/tools/jarsigner/TsacertOptionTest.java @@ -87,6 +87,7 @@ public class TsacertOptionTest { "-storepass", PASSWORD, "-keypass", PASSWORD, "-dname", "CN=CA", + "-ext", "bc:c", "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0); ProcessTools.executeCommand(KEYTOOL, "-genkey", diff --git a/test/sun/security/tools/jarsigner/Warning.java b/test/sun/security/tools/jarsigner/Warning.java index 095d2053438b502b5d4f5bc3d9051faf153ebb31..adb78334843f47c4b7cd054daab068fbae00e0ef 100644 --- a/test/sun/security/tools/jarsigner/Warning.java +++ b/test/sun/security/tools/jarsigner/Warning.java @@ -42,7 +42,7 @@ public class Warning { Files.deleteIfExists(Paths.get("ks")); - newCert("ca", "-validity 365000"); + newCert("ca", "-validity 365000", "-ext bc:c"); recreateJar(); diff --git a/test/sun/security/tools/jarsigner/concise_jarsigner.sh b/test/sun/security/tools/jarsigner/concise_jarsigner.sh index b9ec9e8323229e146fe33a387748a4e6e930feef..b2affb490fbaa903e79d50ff85255c06273dd2e3 100644 --- a/test/sun/security/tools/jarsigner/concise_jarsigner.sh +++ b/test/sun/security/tools/jarsigner/concise_jarsigner.sh @@ -22,7 +22,7 @@ # # @test -# @bug 6802846 8172529 +# @bug 6802846 8172529 8227758 # @summary jarsigner needs enhanced cert validation(options) # # @run shell/timeout=240 concise_jarsigner.sh @@ -207,15 +207,11 @@ $JARSIGNER -strict -keystore $KS -storepass changeit a.jar altchain $JARSIGNER -strict -keystore $KS -storepass changeit -certchain certchain a.jar altchain [ $? = 0 ] || exit $LINENO -# if ca2 is removed, -certchain still work because altchain is a self-signed entry and -# it is trusted by jarsigner +# if ca2 is removed and cert is imported, -certchain won't work because this certificate +# entry is not trusted # save ca2.cert for easy replay $KT -exportcert -file ca2.cert -alias ca2 $KT -delete -alias ca2 -$JARSIGNER -strict -keystore $KS -storepass changeit -certchain certchain a.jar altchain -[ $? = 0 ] || exit $LINENO - -# if cert is imported, -certchain won't work because this certificate entry is not trusted $KT -importcert -file certchain -alias altchain -noprompt $JARSIGNER -strict -keystore $KS -storepass changeit -certchain certchain a.jar altchain [ $? = 4 ] || exit $LINENO @@ -228,8 +224,8 @@ $JARSIGNER -verify a.jar # ========================================================== $KT -genkeypair -alias ee -dname CN=ee -$KT -genkeypair -alias caone -dname CN=caone -$KT -genkeypair -alias catwo -dname CN=catwo +$KT -genkeypair -alias caone -dname CN=caone -ext bc:c +$KT -genkeypair -alias catwo -dname CN=catwo -ext bc:c $KT -certreq -alias ee | $KT -gencert -alias catwo -rfc > ee.cert $KT -certreq -alias catwo | $KT -gencert -alias caone -sigalg MD5withRSA -rfc > catwo.cert diff --git a/test/sun/security/tools/jarsigner/ec.sh b/test/sun/security/tools/jarsigner/ec.sh index 442e854635e67bd038b18f6d22b53a467030eb95..2893dca63f5b8405d234b7caa592873235fadee1 100644 --- a/test/sun/security/tools/jarsigner/ec.sh +++ b/test/sun/security/tools/jarsigner/ec.sh @@ -53,7 +53,7 @@ rm $KS $JFILE echo A > A $JAR cvf $JFILE A -$KT -alias ca -dname CN=ca -keyalg ec -genkey -validity 300 || exit 11 +$KT -alias ca -dname CN=ca -keyalg ec -genkey -validity 300 -ext bc:c || exit 11 $KT -alias a -dname CN=a -keyalg ec -genkey || exit 11 $KT -alias a -certreq | $KT -gencert -alias ca -validity 300 | $KT -import -alias a || exit 111 diff --git a/test/sun/security/tools/jarsigner/onlymanifest.sh b/test/sun/security/tools/jarsigner/onlymanifest.sh index bbc90a1b3a889a067aedbbecdc6c09a6579db418..cc42e8f32afa96baa66f259ea96a5136ec0f2ba3 100644 --- a/test/sun/security/tools/jarsigner/onlymanifest.sh +++ b/test/sun/security/tools/jarsigner/onlymanifest.sh @@ -57,7 +57,7 @@ rm $KS $JFILE 2> /dev/null echo "Key: Value" > manifest $JAR cvfm $JFILE manifest -$KT -alias ca -dname CN=ca -genkey -validity 300 || exit 1 +$KT -alias ca -dname CN=ca -genkey -validity 300 -ext bc:c || exit 1 $KT -alias a -dname CN=a -genkey -validity 300 || exit 2 $KT -alias a -certreq | $KT -gencert -alias ca -validity 300 | $KT -import -alias a || exit 3 $JARSIGNER -keystore $KS -storepass changeit $JFILE a -debug -strict || exit 4 diff --git a/test/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java b/test/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java index 1a49c15d1fd14f343bb68432d68756f28cdb0c8d..bb0f4484f6d61bae2e3315b704cb500b64888c6e 100644 --- a/test/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java +++ b/test/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -53,7 +53,7 @@ public class BadExtendedKeyUsageTest extends Test { // create a certificate whose signer certificate's // ExtendedKeyUsage extension doesn't allow code signing // create key pair for jar signing - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(KEY_ALIAS); issueCert( diff --git a/test/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java b/test/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java index fb0fac9fdc37113f546af0143e2349adc0c82708..46cd5648f2c6eab3722a911dc03fb0cd408085ee 100644 --- a/test/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java +++ b/test/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -53,7 +53,7 @@ public class BadKeyUsageTest extends Test { // create a certificate whose signer certificate's KeyUsage extension // doesn't allow code signing - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(KEY_ALIAS); issueCert( diff --git a/test/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java b/test/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java index 443331ddeec73c5e2f20a359eb8ab4670a1ec844..0d1a063a20f5a27352cfa64aa18f1d77cdac1de9 100644 --- a/test/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java +++ b/test/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -54,7 +54,7 @@ public class BadNetscapeCertTypeTest extends Test { // create a certificate whose signer certificate's // NetscapeCertType extension doesn't allow code signing // create key pair for jar signing - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(KEY_ALIAS); issueCert( diff --git a/test/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java b/test/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java index b9d0ae59ec1af3982922dea92f63095c28a75d40..6055546f275b951db22c46953529c98a0b93c0d0 100644 --- a/test/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java +++ b/test/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -54,7 +54,7 @@ public class ChainNotValidatedTest extends Test { // Root CA is not checked at all. If the intermediate CA has // BasicConstraints extension set to true, it will be valid. // Otherwise, chain validation will fail. - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(CA2_KEY_ALIAS); issueCert(CA2_KEY_ALIAS, "-ext", diff --git a/test/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java b/test/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java index f457776fb658d31b886fdb01604c8f1bd62c5457..1a8ee17081e530c94a97df122dcedd72f9668fde 100644 --- a/test/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java +++ b/test/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -52,7 +52,7 @@ public class HasExpiredCertTest extends Test { JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); // create key pair for jar signing - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(KEY_ALIAS); issueCert( diff --git a/test/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java b/test/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java index 8a71c667807a2aff3cc3d7fd442c619e8ccac72e..c414f48dc7b85b47b057da4795d3edf2cefc9b1e 100644 --- a/test/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java +++ b/test/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -52,7 +52,7 @@ public class HasExpiringCertTest extends Test { JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); // create key pair for jar signing - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(KEY_ALIAS); issueCert( diff --git a/test/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java b/test/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java index 078ff8962dfb1eaf1e8485348ad7d2173ca2460c..1aafc58edbfc6419f2f888c0662fdbca985b3002 100644 --- a/test/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java +++ b/test/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -51,7 +51,7 @@ public class HasUnsignedEntryTest extends Test { JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); // create key pair for signing - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(KEY_ALIAS); issueCert( KEY_ALIAS, diff --git a/test/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java b/test/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java index 862e8cae799ea68536f1f84e8c34a43c53fe748a..0831dc59f29840a6e35ed2d70bcfa001b45a5140 100644 --- a/test/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java +++ b/test/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -54,7 +54,7 @@ public class MultipleWarningsTest extends Test { // create a jar file that contains one class file JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); // create first expired certificate // whose ExtendedKeyUsage extension does not allow code signing diff --git a/test/sun/security/tools/jarsigner/warnings/NoTimestampTest.java b/test/sun/security/tools/jarsigner/warnings/NoTimestampTest.java index 8429fe26b2071ed4469a8908ffc35d46746432bf..447baab0e8259e30459a69c6dc837ae16f7b68fb 100644 --- a/test/sun/security/tools/jarsigner/warnings/NoTimestampTest.java +++ b/test/sun/security/tools/jarsigner/warnings/NoTimestampTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -57,7 +57,7 @@ public class NoTimestampTest extends Test { * 24 * 60 * 60 * 1000L); // create key pair - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(KEY_ALIAS); issueCert(KEY_ALIAS, "-validity", Integer.toString(VALIDITY)); diff --git a/test/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java b/test/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java index 9fb92625f8383c18b8a7c379b2612de0c733bffa..db415f9413e8cebf1d0484a5ccb5ebdc2b197b58 100644 --- a/test/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java +++ b/test/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -49,7 +49,7 @@ public class NotSignedByAliasTest extends Test { Utils.createFiles(FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); // create first key pair for signing createAlias(FIRST_KEY_ALIAS); diff --git a/test/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java b/test/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java index 4d19c9adc9feea3c7d071069673b99ada9e08e6b..a9aa77dc8c2ae068e9087fbc0ff61ac7bcae111d 100644 --- a/test/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java +++ b/test/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -50,7 +50,7 @@ public class NotYetValidCertTest extends Test { JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); // create certificate that will be valid only tomorrow - createAlias(CA_KEY_ALIAS); + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); createAlias(KEY_ALIAS); issueCert( diff --git a/test/sun/security/util/DerValue/BadValue.java b/test/sun/security/util/DerValue/BadValue.java index ef3a9ef3817d2bb83eaa21f52b8a62a53f6ff26b..d02a47896e4d291c7fe2cafc5b1773070f79b65b 100644 --- a/test/sun/security/util/DerValue/BadValue.java +++ b/test/sun/security/util/DerValue/BadValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, 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 @@ -35,43 +35,48 @@ public class BadValue { public static void main(String[] args) throws Exception { - // Test IOUtils.readFully + // Test IOUtils. // We have 4 bytes InputStream in = new ByteArrayInputStream(new byte[10]); - byte[] bs = IOUtils.readFully(in, 4, true); + byte[] bs = IOUtils.readExactlyNBytes(in, 4); if (bs.length != 4 || in.available() != 6) { throw new Exception("First read error"); } // But only 6 left - bs = IOUtils.readFully(in, 10, false); + bs = IOUtils.readNBytes(in, 10); if (bs.length != 6 || in.available() != 0) { throw new Exception("Second read error"); } - // MAX read as much as it can + // MAX length results in exception in = new ByteArrayInputStream(new byte[10]); - bs = IOUtils.readFully(in, Integer.MAX_VALUE, true); - if (bs.length != 10 || in.available() != 0) { - throw new Exception("Second read error"); + try { + bs = IOUtils.readExactlyNBytes(in, Integer.MAX_VALUE); + throw new Exception("No exception on MAX_VALUE length"); + } catch (EOFException ex) { + // this is expected } - // MAX ignore readAll + // -1 length results in exception in = new ByteArrayInputStream(new byte[10]); - bs = IOUtils.readFully(in, Integer.MAX_VALUE, false); - if (bs.length != 10 || in.available() != 0) { - throw new Exception("Second read error"); + try { + bs = IOUtils.readExactlyNBytes(in, -1); + throw new Exception("No exception on -1 length"); + } catch (IOException ex) { + // this is expected } + // 20>10, readAll means failure in = new ByteArrayInputStream(new byte[10]); try { - bs = IOUtils.readFully(in, 20, true); - throw new Exception("Third read error"); + bs = IOUtils.readExactlyNBytes(in, 20); + throw new Exception("No exception on EOF"); } catch (EOFException e) { // OK } int bignum = 10 * 1024 * 1024; - bs = IOUtils.readFully(new SuperSlowStream(bignum), -1, true); + bs = IOUtils.readExactlyNBytes(new SuperSlowStream(bignum), bignum); if (bs.length != bignum) { - throw new Exception("Fourth read error"); + throw new Exception("Read returned small array"); } // Test DerValue diff --git a/test/sun/security/validator/EndEntityExtensionCheck.java b/test/sun/security/validator/EndEntityExtensionCheck.java index 3cff8fcb5ee1cf3f80bbea9fd0306d1bb1504384..72db2776446cdab4f0390c7911718b1ae9eebf6b 100644 --- a/test/sun/security/validator/EndEntityExtensionCheck.java +++ b/test/sun/security/validator/EndEntityExtensionCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -26,6 +26,7 @@ * @bug 8076117 * @summary EndEntityChecker should not process custom extensions * after PKIX validation + * @run main/othervm -Djdk.security.allowNonCaAnchor EndEntityExtensionCheck */ import java.io.ByteArrayInputStream;