449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings/*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * The contents of this file are subject to the terms
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * of the Common Development and Distribution License
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * (the License). You may not use this file except in
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * compliance with the License.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * You can obtain a copy of the License at
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * https://opensso.dev.java.net/public/CDDLv1.0.html or
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * opensso/legal/CDDLv1.0.txt
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * See the License for the specific language governing
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * permission and limitations under the License.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * When distributing Covered Code, include this CDDL
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Header Notice in each file and include the License file
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * at opensso/legal/CDDLv1.0.txt.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * If applicable, add the following below the CDDL Header,
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * with the fields enclosed by brackets [] replaced by
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * your own identifying information:
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * "Portions Copyrighted [year] [name of copyright owner]"
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * $Id: QuerySignatureUtil.java,v 1.2 2008/06/25 05:47:45 qcheng Exp $
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings * Portions Copyrighted 2015 ForgeRock AS.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterpackage com.sun.identity.saml2.common;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbingsimport java.security.GeneralSecurityException;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbingsimport java.util.Set;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport java.util.StringTokenizer;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport java.security.PrivateKey;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport java.security.Signature;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport java.security.SignatureException;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport java.security.InvalidKeyException;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport java.security.cert.X509Certificate;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbingsimport com.sun.identity.shared.configuration.SystemPropertiesManager;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport com.sun.identity.shared.encode.Base64;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport com.sun.identity.shared.encode.URLEncDec;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport com.sun.identity.saml.common.SAMLConstants;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbingsimport org.apache.xml.security.Init;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbingsimport org.apache.xml.security.algorithms.JCEMapper;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbingsimport org.apache.xml.security.signature.XMLSignature;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbingsimport org.forgerock.openam.utils.StringUtils;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterimport java.security.NoSuchAlgorithmException;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/**
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * The <code>QuerySignatureUtil</code> provides methods to
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * sign query string and to verify signature on query string
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterpublic class QuerySignatureUtil {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings private static final String SIGNATURE = "Signature";
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings static {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings Init.init();
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster private QuerySignatureUtil() {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /**
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Signs the query string.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param queryString Query String
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param privateKey siging key
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @return String signed query string
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @exception SAML2Exception if the signing fails
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings public static String sign(String queryString, PrivateKey privateKey) throws SAML2Exception {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String classMethod =
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "QuerySignatureUtil.sign: ";
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (queryString == null ||
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster queryString.length() == 0 ||
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster privateKey == null) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.error(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Either input query string or private key is null."
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster );
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster throw new SAML2Exception(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.bundle.getString("nullInput"));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (SAML2Utils.debug.messageEnabled()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.message(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Input query string:\n" +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster queryString);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings final String querySigAlg;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings final String alg = privateKey.getAlgorithm();
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings switch (alg) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings case "RSA":
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings //Defaulting to RSA-SHA1 for the sake of interoperability
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings querySigAlg = SystemPropertiesManager.get(SAML2Constants.QUERY_SIGNATURE_ALGORITHM_RSA,
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings break;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings case "DSA":
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings //Defaulting to SHA1WithDSA as JDK7 does not support SHA256WithDSA
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings querySigAlg = SystemPropertiesManager.get(SAML2Constants.QUERY_SIGNATURE_ALGORITHM_DSA,
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings XMLSignature.ALGO_ID_SIGNATURE_DSA);
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings break;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings case "EC":
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings querySigAlg = SystemPropertiesManager.get(SAML2Constants.QUERY_SIGNATURE_ALGORITHM_EC,
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA512);
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings break;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings default:
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings SAML2Utils.debug.error(classMethod + "Private Key algorithm not supported: " + alg);
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings throw new SAML2Exception(SAML2Utils.bundle.getString("algorithmNotSupported"));
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings Signature sig;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings try {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings sig = Signature.getInstance(JCEMapper.translateURItoJCEID(querySigAlg));
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings } catch (NoSuchAlgorithmException nsae) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings throw new SAML2Exception(nsae);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if(queryString.charAt(queryString.length()-1)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster != '&'){
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster queryString = queryString + "&";
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings queryString += SAML2Constants.SIG_ALG + "=" + URLEncDec.encode(querySigAlg);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (SAML2Utils.debug.messageEnabled()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.message(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Final string to be signed:\n" +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster queryString);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings byte[] sigBytes;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster try {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings sig.initSign(privateKey);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster sig.update(queryString.getBytes());
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster sigBytes = sig.sign();
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings } catch (GeneralSecurityException gse) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings throw new SAML2Exception(gse);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (sigBytes == null ||
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster sigBytes.length == 0) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.error(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Generated signature is null");
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster throw new SAML2Exception(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.bundle.getString(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "nullSigGenerated"
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster )
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster );
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster Base64 encoder = new Base64();
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String encodedSig = encoder.encode(sigBytes);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster queryString +=
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "&" + SAML2Constants.SIGNATURE + "=" +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster URLEncDec.encode(encodedSig);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (SAML2Utils.debug.messageEnabled()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.message(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Signed query string:\n" +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster queryString);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return queryString;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /**
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings * Verifies the query string signature.
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings *
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings * @param queryString Signed query String.
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings * @param verificationCerts Verification certificates.
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings * @return boolean whether the verification is successful or not.
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings * @throws SAML2Exception if there is an error during verification.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster public static boolean verify(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String queryString,
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings Set<X509Certificate> verificationCerts
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ) throws SAML2Exception {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String classMethod =
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "QuerySignatureUtil.verify: ";
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (queryString == null ||
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings queryString.length() == 0 || verificationCerts.isEmpty()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.error(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Input query string or certificate is null");
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster throw new SAML2Exception(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.bundle.getString("nullInput"));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (SAML2Utils.debug.messageEnabled()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.message(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Query string to be verifed:\n" + queryString);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster StringTokenizer st = new
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster StringTokenizer(queryString, "&");
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String token = null;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String samlReq = null;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String samlRes = null;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String relay = null;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String sigAlg = null;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String encSig = null;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster while (st.hasMoreTokens()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster token = st.nextToken();
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (token.startsWith(SAML2Constants.SAML_REQUEST)) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster samlReq=token;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster } else if (token.startsWith(SAML2Constants.SAML_RESPONSE)) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster samlRes=token;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster } else if (token.startsWith(SAML2Constants.RELAY_STATE)) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster relay=token;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster } else if (token.startsWith(SAML2Constants.SIG_ALG)) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster sigAlg = token;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster } else if (token.startsWith(SAML2Constants.SIGNATURE)) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster encSig = token;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (sigAlg == null || sigAlg.equals("")) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.error(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Null SigAlg query parameter.");
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster throw new SAML2Exception(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.bundle.getString("nullSigAlg"));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (encSig == null || encSig.equals("")) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.error(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Null Signature query parameter.");
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster throw new SAML2Exception(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.bundle.getString("nullSig"));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster // The following manipulation is necessary because
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster // other implementations could send the query
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster // parameters out of order, i.e., not in the same
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster // order when signature is produced
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String newQueryString = null;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (samlReq != null) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster newQueryString = samlReq;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster } else {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster newQueryString = samlRes;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (relay != null) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster newQueryString += "&"+relay;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster newQueryString += "&"+sigAlg;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (SAML2Utils.debug.messageEnabled()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.message(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod+
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Query string to be verifed (re-arranged):\n" +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster newQueryString);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster int sigAlgValueIndex = sigAlg.indexOf('=');
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String sigAlgValue =
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster sigAlg.substring(sigAlgValueIndex+1);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (sigAlgValue == null || sigAlgValue.equals("")) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.error(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Null SigAlg query parameter value.");
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster throw new SAML2Exception(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.bundle.getString("nullSigAlg"));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster sigAlgValue = URLEncDec.decode(sigAlgValue);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (SAML2Utils.debug.messageEnabled()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.message(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "SigAlg query parameter value: " +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster sigAlgValue);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster int encSigValueIndex = encSig.indexOf('=');
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster String encSigValue =
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster encSig.substring(encSigValueIndex+1);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (encSigValue == null || encSigValue.equals("")) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.message(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Null Signature query parameter value.");
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster throw new SAML2Exception(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.bundle.getString("nullSig"));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster encSigValue = URLEncDec.decode(encSigValue);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (SAML2Utils.debug.messageEnabled()) {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster SAML2Utils.debug.message(
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster classMethod +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster "Signature query parameter value:\n" +
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster encSigValue);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster // base-64 decode the signature value
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster byte[] signature = null;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster Base64 decoder = new Base64();
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster signature = decoder.decode(encSigValue);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster // get Signature instance based on algorithm
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings if (!SIGNATURE.equals(JCEMapper.getAlgorithmClassFromURI(sigAlgValue))) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings SAML2Utils.debug.error(classMethod + "Signature algorithm " + sigAlgValue + " is not supported.");
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings throw new SAML2Exception(SAML2Utils.bundle.getString("algNotSupported"));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings Signature sig;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster try {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings sig = Signature.getInstance(JCEMapper.translateURItoJCEID(sigAlgValue));
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings } catch (NoSuchAlgorithmException nsae) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings throw new SAML2Exception(nsae);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings return isValidSignature(sig, verificationCerts, newQueryString.getBytes(), signature);
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings private static boolean isValidSignature(Signature sig, Set<X509Certificate> certificates, byte[] queryString,
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings byte[] signature) throws SAML2Exception {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings final String classMethod = "QuerySignatureUtil.isValidSignature: ";
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings Exception firstException = null;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings for (X509Certificate certificate : certificates) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings try {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings sig.initVerify(certificate);
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings sig.update(queryString);
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings if (sig.verify(signature)) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings return true;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings } catch (InvalidKeyException | SignatureException ex) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings SAML2Utils.debug.warning(classMethod + "Signature validation failed due to " + ex);
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings if (firstException == null) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings firstException = ex;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings if (firstException != null) {
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings throw new SAML2Exception(firstException);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings return false;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}