17c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/*
27c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Copyright (C) 2009 Google Inc.  All rights reserved.
37c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
47c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Licensed under the Apache License, Version 2.0 (the "License");
57c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * you may not use this file except in compliance with the License.
67c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * You may obtain a copy of the License at
77c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
87c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *      http://www.apache.org/licenses/LICENSE-2.0
97c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Unless required by applicable law or agreed to in writing, software
117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * distributed under the License is distributed on an "AS IS" BASIS,
127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * See the License for the specific language governing permissions and
147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * limitations under the License.
157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpackage com.google.polo.pairing;
187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.exception.PoloException;
207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.math.BigInteger;
227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.security.cert.Certificate;
237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport javax.net.ssl.SSLPeerUnverifiedException;
257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport javax.net.ssl.SSLSession;
267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/**
287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Utility methods of general usefulness to the Polo library.
297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpublic class PoloUtil {
317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Returns the peer {@link Certificate} for an {@link SSLSession}.
347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *
357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @throws PoloException  if the peer certificate could not be obtained
367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *                        from the {@link SSLSession}.
377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @return                the {@link Certificate} of the peer
387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public static Certificate getPeerCert(SSLSession session)
407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      throws PoloException {
417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    try {
427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      // Peer certificate
437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      Certificate[] certs = session.getPeerCertificates();
447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      if (certs == null || certs.length < 1) {
457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        throw new PoloException("No peer certificate.");
467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      }
477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      return certs[0];
487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    } catch (SSLPeerUnverifiedException e) {
497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      throw new PoloException(e);
507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Return the local {@link Certificate} for an {@link SSLSession}.
557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *
567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @throws PoloException  if the local certificate could not be obtained
577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *                        from the {@link SSLSession}
587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @return                the {@link Certificate} of the peer
597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public static Certificate getLocalCert(SSLSession session)
617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      throws PoloException {
627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    Certificate[] certs = session.getLocalCertificates();
637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    if (certs == null || certs.length < 1) {
647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      throw new PoloException("No local certificate.");
657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return certs[0];
677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Converts an array of bytes to a string of hexadecimal characters.
717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Leading null bytes are preserved in the output.
727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * <p>
737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * The input byte stream is assumed to be a positive, two's complement
747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * representation of an integer.  The return value is the hexadecimal string
757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * representation of this value.
767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *
777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @param bytes  the bytes to convert
787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @return       the string representation
797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public static String bytesToHexString(byte[] bytes) {
817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    if (bytes == null || bytes.length == 0) {
827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      return "";
837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    BigInteger bigint = new BigInteger(1, bytes);
857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    int formatLen = bytes.length * 2;
867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return String.format("%0" + formatLen + "x", bigint);
877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Converts a string of hex characters to a byte array.
917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   *
927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @param hexstr  the string of hex characters
937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * @return        a byte array representation
947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public static byte[] hexStringToBytes(String hexstr) {
967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    if (hexstr == null || hexstr.length() == 0 || (hexstr.length() % 2) != 0) {
977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      throw new IllegalArgumentException("Bad input string.");
987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] result = new byte[hexstr.length() / 2];
1017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    for (int i=0; i < result.length; i++) {
1027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet      result[i] = (byte) Integer.parseInt(hexstr.substring(2 * i, 2 * (i + 1)),
1037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet          16);
1047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return result;
1067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
1077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
1097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Converts an integer value to the big endian 4-byte representation.
1107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
1117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public static final byte[] intToBigEndianIntBytes(int intVal) {
1127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    byte[] outBuf = new byte[4];
1137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    outBuf[0] = (byte)((intVal >> 24) & 0xff);
1147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    outBuf[1] = (byte)((intVal >> 16) & 0xff);
1157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    outBuf[2] = (byte)((intVal >> 8) & 0xff);
1167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    outBuf[3] = (byte)(intVal & 0xff);
1177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return outBuf;
1187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
1197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  /**
1217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   * Converts a 4-byte array of bytes to an unsigned long value.
1227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet   */
1237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  public static final long intBigEndianBytesToLong(byte[] input) {
1247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    assert (input.length == 4);
1257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    long ret = (long)(input[0]) & 0xff;
1267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    ret <<= 8;
1277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    ret |= (long)(input[1]) & 0xff;
1287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    ret <<= 8;
1297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    ret |= (long)(input[2]) & 0xff;
1307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    ret <<= 8;
1317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    ret |= (long)(input[3]) & 0xff;
1327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    return ret;
1337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet  }
1347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
136