/****************************************************************************
* Copyright (C) 2013 HS Coburg.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file is part of the Open eCard App.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License version 3.0 as published by the Free Software Foundation
* and appearing in the file LICENSE.GPL included in the packaging of
* this file. Please review the following information to ensure the
* GNU General Public License version 3.0 requirements will be met:
* http://www.gnu.org/copyleft/gpl.html.
*
* Other Usage
* Alternatively, this file may be used in accordance with the terms
* and conditions contained in a signed written agreement between
* you and ecsec GmbH.
*
***************************************************************************/
package org.openecard.common.util;
import java.io.IOException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import org.openecard.bouncycastle.crypto.tls.Certificate;
import org.openecard.common.tlv.TLV;
import org.openecard.common.tlv.TLVException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A set of utility functions used in connection with the TC Token.
*
* @author Dirk Petrautzki <petrautzki@hs-coburg.de>
*/
public class TR03112Utils {
private static final Logger logger = LoggerFactory.getLogger(TR03112Utils.class.getName());
private static final int TAG_OCTET_STRING = 0x04;
private static final String SHA256 = "SHA-256";
/**
* Check if the two given URLs comply the Same-Origin-Policy.
*
* @param url1 the first URL
* @param url2 the second URL
* @return {@code true} if the Same-Origin-Policy has been complied with, {@code false} otherwise
*/
public static boolean checkSameOriginPolicy(URL url1, URL url2) {
logger.debug("Checking SOP for {} and {}.", url1, url2);
String endpointProtocol = url1.getProtocol();
String subjectProtocol = url2.getProtocol();
if (!endpointProtocol.equals(subjectProtocol)) {
logger.error("SOP violated; the protocols do not match.");
return false;
}
String endpointHost = url1.getHost();
String subjectHost = url2.getHost();
if (!endpointHost.equals(subjectHost)) {
logger.error("SOP violated; the hosts do not match.");
return false;
}
int endpointPort = url1.getPort();
if (endpointPort == -1) {
endpointPort = url1.getDefaultPort();
}
int subjectPort = url2.getPort();
if (subjectPort == -1) {
subjectPort = url2.getDefaultPort();
}
if (!(endpointPort == subjectPort)) {
logger.error("SOP violated; the ports do not match");
return false;
}
return true;
}
/**
* Check if the hash of the retrieved server certificate is contained in the CommCertificates of the
* CertificateDescription extension of the eService certificate.
*
* @param serverCertificate the retrieved server certificate
* @param commCertificates List of hashes of the communication certificates as obtained from the
* CertificateDescription
* @return {@code true} if the hash is contained; {@code false} otherwise
*/
public static boolean isInCommCertificates(Certificate serverCertificate, List<byte[]> commCertificates) {
try {
// calculate hash of first certificate in chain
MessageDigest md = MessageDigest.getInstance(SHA256);
md.update(serverCertificate.getCertificateAt(0).getEncoded());
byte[] hash = md.digest();
// prepend with tag
TLV tlv = new TLV();
tlv.setTagNumWithClass(TAG_OCTET_STRING);
tlv.setValue(hash);
byte[] hashTag = tlv.toBER();
if (logger.isDebugEnabled()) {
logger.debug("Hash (with tag) of the retrieved server certificate: {}", ByteUtils.toHexString(hashTag));
}
// finally check if contained in the CommCertificates
for (byte[] commCertificate : commCertificates) {
logger.debug("CommCertificate: {}", ByteUtils.toHexString(commCertificate));
if (ByteUtils.compare(commCertificate, hashTag)) {
return true;
}
}
} catch (NoSuchAlgorithmException e) {
logger.error("SHA-256 digest algorithm is not available.");
return false;
} catch (TLVException e) {
logger.error("TLV construction failed.");
return false;
} catch (IOException e) {
logger.error("Server certificate couldn't be encoded.");
return false;
}
return false;
}
/**
* Check if the given status code indicates a redirect (301, 302, 303, 307).
*
* @param statusCode the status code to check
* @return {@code true} if the status code indicates a redirect, {@code false} otherwise
*/
public static boolean isRedirectStatusCode(int statusCode) {
switch (statusCode) {
// TODO check why 301 is not mentioned in TR
case 301: // fall through
case 302: // fall through
case 303: // fall through
case 307:
return true;
default:
return false;
}
}
}