001/*******************************************************************************
002 * Copyright 2017 The MIT Internet Trust Consortium
003 *
004 * Portions copyright 2011-2013 The MITRE Corporation
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 *******************************************************************************/
018
019package org.mitre.openid.connect.util;
020
021import java.security.MessageDigest;
022import java.security.NoSuchAlgorithmException;
023import java.util.Arrays;
024
025import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029import com.nimbusds.jose.JWSAlgorithm;
030import com.nimbusds.jose.util.Base64URL;
031
032/**
033 * Utility class for generating hashes for access tokens and authorization codes
034 * to be included in an ID Token.
035 *
036 * @author Amanda Anganes
037 *
038 */
039public class IdTokenHashUtils {
040
041        /**
042         * Logger for this class
043         */
044        private static final Logger logger = LoggerFactory.getLogger(IdTokenHashUtils.class);
045
046        /**
047         * Compute the SHA hash of an authorization code
048         *
049         * @param signingAlg
050         * @param code
051         * @return
052         */
053        public static Base64URL getCodeHash(JWSAlgorithm signingAlg, String code) {
054                return getHash(signingAlg, code.getBytes());
055        }
056
057        /**
058         * Compute the SHA hash of a token
059         *
060         * @param signingAlg
061         * @param token
062         * @return
063         */
064        public static Base64URL getAccessTokenHash(JWSAlgorithm signingAlg, OAuth2AccessTokenEntity token) {
065
066                byte[] tokenBytes = token.getJwt().serialize().getBytes();
067
068                return getHash(signingAlg, tokenBytes);
069
070        }
071
072        public static Base64URL getHash(JWSAlgorithm signingAlg, byte[] bytes) {
073
074                //Switch based on the given signing algorithm - use SHA-xxx with the same 'xxx' bitnumber
075                //as the JWSAlgorithm to hash the token.
076                String hashAlg = null;
077
078                if (signingAlg.equals(JWSAlgorithm.HS256) || signingAlg.equals(JWSAlgorithm.ES256) || signingAlg.equals(JWSAlgorithm.RS256) || signingAlg.equals(JWSAlgorithm.PS256)) {
079                        hashAlg = "SHA-256";
080                }
081
082                else if (signingAlg.equals(JWSAlgorithm.ES384) || signingAlg.equals(JWSAlgorithm.HS384) || signingAlg.equals(JWSAlgorithm.RS384) || signingAlg.equals(JWSAlgorithm.PS384)) {
083                        hashAlg = "SHA-384";
084                }
085
086                else if (signingAlg.equals(JWSAlgorithm.ES512) || signingAlg.equals(JWSAlgorithm.HS512) || signingAlg.equals(JWSAlgorithm.RS512) || signingAlg.equals(JWSAlgorithm.PS512)) {
087                        hashAlg = "SHA-512";
088                }
089
090                if (hashAlg != null) {
091
092                        try {
093                                MessageDigest hasher = MessageDigest.getInstance(hashAlg);
094                                hasher.reset();
095                                hasher.update(bytes);
096
097                                byte[] hashBytes = hasher.digest();
098                                byte[] hashBytesLeftHalf = Arrays.copyOf(hashBytes, hashBytes.length / 2);
099                                Base64URL encodedHash = Base64URL.encode(hashBytesLeftHalf);
100
101                                return encodedHash;
102
103                        } catch (NoSuchAlgorithmException e) {
104
105                                logger.error("No such algorithm error: ", e);
106
107                        }
108
109                }
110
111                return null;
112        }
113
114}