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}