blob: e487c8b0529fe471954726ff28b9b7a84d100a65 [file] [log] [blame]
/*
* $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.16/src/java/org/apache/commons/ssl/Util.java $
* $Revision: 180 $
* $Date: 2014-09-23 11:33:47 -0700 (Tue, 23 Sep 2014) $
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.kerby.util;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
/**
* @author Credit Union Central of British Columbia
* @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
* @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
* @since 28-Feb-2006
*/
public class Util {
public static final int SIZE_KEY = 0;
public static final int LAST_READ_KEY = 1;
/**
* True if the Keystores have the same # of entries, have the same set of aliases, and all the certificate-chains
* (of the certificate entries) match. Does not check the private keys for equality, since we
* don't bother taking the passwords to get at them.
* @param ks1 The first key store
* @param ks2 The second key store
* @return boolean
* @throws KeyStoreException e
*/
public static boolean equals(KeyStore ks1, KeyStore ks2) throws KeyStoreException {
if (ks1 == null || ks2 == null) {
return ks1 == null && ks2 == null;
}
Set<String> aliases1 = aliases(ks1);
Set<String> aliases2 = aliases(ks2);
if (aliases1.equals(aliases2)) {
for (String s : aliases1) {
if (ks1.isCertificateEntry(s) != ks2.isCertificateEntry(s)) {
return false;
}
if (ks1.isKeyEntry(s) != ks2.isKeyEntry(s)) {
return false;
}
if (ks1.isCertificateEntry(s)) {
Certificate[] cc1 = ks1.getCertificateChain(s);
Certificate[] cc2 = ks2.getCertificateChain(s);
if (!Arrays.equals(cc1, cc2)) {
return false;
}
Certificate c1 = ks1.getCertificate(s);
Certificate c2 = ks2.getCertificate(s);
if (!c1.equals(c2)) {
return false;
}
}
// should we bother checking keys? maybe one day....
}
}
return true;
}
private static Set<String> aliases(KeyStore ks) throws KeyStoreException {
Set<String> aliases = new TreeSet<>();
Enumeration<String> en = ks.aliases();
while (en.hasMoreElements()) {
aliases.add(en.nextElement());
}
return aliases;
}
public static boolean isYes(String yesString) {
if (yesString == null) {
return false;
}
String s = yesString.trim().toUpperCase();
return "1".equals(s) || "YES".equals(s) || "TRUE".equals(s)
|| "ENABLE".equals(s) || "ENABLED".equals(s) || "Y".equals(s)
|| "ON".equals(s);
}
public static String trim(final String s) {
if (s == null || "".equals(s)) {
return s;
}
int i = 0;
int j = s.length() - 1;
while (isWhiteSpace(s.charAt(i))) {
i++;
}
while (isWhiteSpace(s.charAt(j))) {
j--;
}
return j >= i ? s.substring(i, j + 1) : "";
}
public static boolean isWhiteSpace(final char c) {
switch (c) {
case 0:
case ' ':
case '\t':
case '\n':
case '\r':
case '\f':
return true;
default:
return false;
}
}
public static void pipeStream(InputStream in, OutputStream out)
throws IOException {
pipeStream(in, out, true);
}
public static void pipeStream(InputStream in, OutputStream out,
boolean autoClose)
throws IOException {
byte[] buf = new byte[8192];
IOException ioe = null;
try {
int bytesRead = in.read(buf);
while (bytesRead >= 0) {
if (bytesRead > 0) {
out.write(buf, 0, bytesRead);
}
bytesRead = in.read(buf);
}
} finally {
// Probably it's best to let consumer call "close", but I'm usually
// the consumer, and I want to be lazy. [Julius, November 20th, 2006]
try {
in.close();
} catch (IOException e) {
ioe = e;
}
if (autoClose) {
try {
out.close();
} catch (IOException e) {
ioe = e;
}
}
}
if (ioe != null) {
throw ioe;
}
}
public static byte[] fileToBytes(final File f) throws IOException {
return streamToBytes(Files.newInputStream(f.toPath()));
}
public static byte[] streamToBytes(final ByteArrayInputStream in,
int maxLength) {
byte[] buf = new byte[maxLength];
int[] status = fill(buf, 0, in);
int size = status[SIZE_KEY];
if (buf.length != size) {
byte[] smallerBuf = new byte[size];
System.arraycopy(buf, 0, smallerBuf, 0, size);
buf = smallerBuf;
}
return buf;
}
public static byte[] streamToBytes(final InputStream in, int maxLength)
throws IOException {
byte[] buf = new byte[maxLength];
int[] status = fill(buf, 0, in);
int size = status[SIZE_KEY];
if (buf.length != size) {
byte[] smallerBuf = new byte[size];
System.arraycopy(buf, 0, smallerBuf, 0, size);
buf = smallerBuf;
}
return buf;
}
public static byte[] streamToBytes(final InputStream in) throws IOException {
byte[] buf = new byte[4096];
try {
int[] status = fill(buf, 0, in);
int size = status[SIZE_KEY];
int lastRead = status[LAST_READ_KEY];
while (lastRead != -1) {
buf = resizeArray(buf);
status = fill(buf, size, in);
size = status[SIZE_KEY];
lastRead = status[LAST_READ_KEY];
}
if (buf.length != size) {
byte[] smallerBuf = new byte[size];
System.arraycopy(buf, 0, smallerBuf, 0, size);
buf = smallerBuf;
}
} finally {
in.close();
}
return buf;
}
public static byte[] streamToBytes(final ByteArrayInputStream in) {
byte[] buf = new byte[4096];
int[] status = fill(buf, 0, in);
int size = status[SIZE_KEY];
int lastRead = status[LAST_READ_KEY];
while (lastRead != -1) {
buf = resizeArray(buf);
status = fill(buf, size, in);
size = status[SIZE_KEY];
lastRead = status[LAST_READ_KEY];
}
if (buf.length != size) {
byte[] smallerBuf = new byte[size];
System.arraycopy(buf, 0, smallerBuf, 0, size);
buf = smallerBuf;
}
// in.close(); <-- this is a no-op on ByteArrayInputStream.
return buf;
}
public static int[] fill(final byte[] buf, final int offset,
final InputStream in)
throws IOException {
int read = in.read(buf, offset, buf.length - offset);
int lastRead = read;
if (read == -1) {
read = 0;
}
while (lastRead != -1 && read + offset < buf.length) {
lastRead = in.read(buf, offset + read, buf.length - read - offset);
if (lastRead != -1) {
read += lastRead;
}
}
return new int[]{offset + read, lastRead};
}
public static int[] fill(final byte[] buf, final int offset,
final ByteArrayInputStream in) {
int read = in.read(buf, offset, buf.length - offset);
int lastRead = read;
if (read == -1) {
read = 0;
}
while (lastRead != -1 && read + offset < buf.length) {
lastRead = in.read(buf, offset + read, buf.length - read - offset);
if (lastRead != -1) {
read += lastRead;
}
}
return new int[]{offset + read, lastRead};
}
public static byte[] resizeArray(final byte[] bytes) {
byte[] biggerBytes = new byte[bytes.length * 2];
System.arraycopy(bytes, 0, biggerBytes, 0, bytes.length);
return biggerBytes;
}
public static String pad(String s, final int length, final boolean left) {
if (s == null) {
s = "";
}
int diff = length - s.length();
if (diff == 0) {
return s;
} else if (diff > 0) {
StringBuilder sb = new StringBuilder();
if (left) {
for (int i = 0; i < diff; i++) {
sb.append(' ');
}
}
sb.append(s);
if (!left) {
for (int i = 0; i < diff; i++) {
sb.append(' ');
}
}
return sb.toString();
} else {
return s;
}
}
public static HostPort toAddress(final String target,
final int defaultPort)
throws UnknownHostException {
String host = target;
int port = defaultPort;
StringTokenizer st = new StringTokenizer(target, ":");
if (st.hasMoreTokens()) {
host = st.nextToken().trim();
}
if (st.hasMoreTokens()) {
port = Integer.parseInt(st.nextToken().trim());
}
if (st.hasMoreTokens()) {
throw new IllegalArgumentException("Invalid host: " + target);
}
return new HostPort(host, port);
}
public static String cipherToAuthType(String cipher) {
if (cipher == null) {
return null;
}
// SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA ==> "DHE_DSS_EXPORT"
// SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA ==> "DHE_DSS"
// SSL_RSA_WITH_3DES_EDE_CBC_SHA ==> "RSA"
StringTokenizer st = new StringTokenizer(cipher.trim(), "_");
if (st.hasMoreTokens()) {
st.nextToken(); // always skip first token
}
if (st.hasMoreTokens()) {
String tok = st.nextToken();
StringBuilder buf = new StringBuilder();
buf.append(tok);
if (st.hasMoreTokens()) {
tok = st.nextToken();
while (!"WITH".equalsIgnoreCase(tok)) {
buf.append('_');
buf.append(tok);
tok = st.nextToken();
}
}
return buf.toString();
}
throw new IllegalArgumentException("not a valid cipher: " + cipher);
}
/**
* Utility method to make sure IP-literals don't trigger reverse-DNS lookups.
* @param s The string
* @return The InetAddress
* @throws UnknownHostException e
*/
public static InetAddress toInetAddress(String s) throws UnknownHostException {
byte[] ip = IPAddressParser.parseIPv4Literal(s);
if (ip == null) {
ip = IPAddressParser.parseIPv6Literal(s);
}
if (ip != null) {
// Strangely, this prevents Java's annoying SSL reverse-DNS lookup that it
// normally does, even with literal IP addresses.
return InetAddress.getByAddress(s, ip);
} else {
return InetAddress.getByName(s);
}
}
public static void main(String[] args) throws Exception {
String s = "line1\n\rline2\n\rline3";
ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes(Charset.forName("UTF-8")));
ByteArrayReadLine readLine = new ByteArrayReadLine(in);
String line = readLine.next();
while (line != null) {
System.out.println(line);
line = readLine.next();
}
System.out.println("--------- test 2 ----------");
s = "line1\n\rline2\n\rline3\n\r\n\r";
in = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
readLine = new ByteArrayReadLine(in);
line = readLine.next();
while (line != null) {
System.out.println(line);
line = readLine.next();
}
}
}