001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * 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 distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.openid.connect.sdk.claims;
019
020
021import java.nio.charset.StandardCharsets;
022import java.security.MessageDigest;
023import java.security.NoSuchAlgorithmException;
024import java.util.Arrays;
025
026import com.nimbusds.jose.JWSAlgorithm;
027import com.nimbusds.jose.jwk.Curve;
028import com.nimbusds.jose.util.Base64URL;
029import com.nimbusds.oauth2.sdk.id.Identifier;
030
031
032/**
033 * The base class for SHA-2 based claims.
034 */
035public abstract class HashClaim extends Identifier {
036        
037        
038        private static final long serialVersionUID = -3163141692378087888L;
039        
040        
041        /**
042         * Creates a new SHA-2 based claim with the specified value.
043         *
044         * @param value The claim value. Must not be {@code null}.
045         */
046        protected HashClaim(final String value) {
047
048                super(value);
049        }
050
051
052        /**
053         * Gets the matching SHA-2 message digest for the specified JSON Web
054         * Signature (JWS) algorithm.
055         *
056         * @param alg The JWS algorithm. Must not be {@code null}.
057         *
058         * @return The SHA-2 message digest, {@code null} if the JWS algorithm
059         *         or its corresponding SHA-2 message digest are not supported.
060         *
061         * @deprecated Use {@link #getMessageDigestInstance(JWSAlgorithm, Curve)}
062         * instead.
063         */
064        @Deprecated
065        public static MessageDigest getMessageDigestInstance(final JWSAlgorithm alg) {
066
067                return getMessageDigestInstance(alg, null);
068        }
069
070
071        /**
072         * Gets the matching SHA-2 message digest for the specified JSON Web
073         * Signature (JWS) algorithm.
074         *
075         * @param alg The JWS algorithm. Must not be {@code null}.
076         * @param crv The JWK curve used with the JWS algorithm, {@code null}
077         *            if not applicable.
078         *
079         * @return The SHA-2 message digest, {@code null} if the JWS algorithm
080         *         or its corresponding SHA-2 message digest are not supported.
081         */
082        public static MessageDigest getMessageDigestInstance(final JWSAlgorithm alg,
083                                                             final Curve crv) {
084
085                String mdAlg;
086
087                if (alg.equals(JWSAlgorithm.HS256) ||
088                    alg.equals(JWSAlgorithm.RS256) ||
089                    alg.equals(JWSAlgorithm.ES256) ||
090                    alg.equals(JWSAlgorithm.ES256K) ||
091                    alg.equals(JWSAlgorithm.PS256)    ) {
092
093                        mdAlg = "SHA-256";
094
095                } else if (alg.equals(JWSAlgorithm.HS384) ||
096                           alg.equals(JWSAlgorithm.RS384) ||
097                           alg.equals(JWSAlgorithm.ES384) ||
098                           alg.equals(JWSAlgorithm.PS384)    ) {
099
100                        mdAlg = "SHA-384";
101
102                } else if (alg.equals(JWSAlgorithm.HS512) ||
103                           alg.equals(JWSAlgorithm.RS512) ||
104                           alg.equals(JWSAlgorithm.ES512) ||
105                           alg.equals(JWSAlgorithm.PS512) ||
106                           alg.equals(JWSAlgorithm.EdDSA) && Curve.Ed25519.equals(crv)) {
107
108                        mdAlg = "SHA-512";
109
110                } else {
111                        // unsupported JWS alg
112                        return null;
113                }
114
115                try {
116                        return MessageDigest.getInstance(mdAlg);
117
118                } catch (NoSuchAlgorithmException e) {
119
120                        // unsupported SHA-2 alg
121                        return null;
122                }
123        }
124
125
126        /**
127         * Computes the SHA-2 claim value for the specified identifier.
128         *
129         * @param identifier The identifier, typically an authorisation code or
130         *                   an access token.  Must not be {@code null}.
131         * @param alg        The reference JWS algorithm. Must not be
132         *                   {@code null}.
133         *
134         * @return The matching (truncated to first half) SHA-2 claim value,
135         *         or {@code null} if the JWS algorithm or its corresponding
136         *         SHA-2 message digest are not supported.
137         *
138         * @deprecated Use {@link #computeValue(Identifier, JWSAlgorithm, Curve)}
139         * instead.
140         */
141        @Deprecated
142        public static String computeValue(final Identifier identifier,
143                                          final JWSAlgorithm alg) {
144
145                return computeValue(identifier, alg, null);
146        }
147
148
149        /**
150         * Computes the SHA-2 claim value for the specified identifier.
151         *
152         * @param identifier The identifier, typically an authorisation code or
153         *                   an access token.  Must not be {@code null}.
154         * @param alg        The reference JWS algorithm. Must not be
155         *                   {@code null}.
156         * @param crv        The JWK curve used with the JWS algorithm,
157         *                   {@code null} if not applicable.
158         *
159         * @return The matching (truncated to first half) SHA-2 claim value,
160         *         or {@code null} if the JWS algorithm or its corresponding
161         *         SHA-2 message digest are not supported.
162         */
163        public static String computeValue(final Identifier identifier,
164                                          final JWSAlgorithm alg,
165                                          final Curve crv) {
166
167                MessageDigest md = getMessageDigestInstance(alg, crv);
168
169                if (md == null)
170                        return null;
171
172                md.update(identifier.getValue().getBytes(StandardCharsets.US_ASCII));
173
174                byte[] hash = md.digest();
175
176                byte[] firstHalf = Arrays.copyOf(hash, hash.length / 2);
177
178                return Base64URL.encode(firstHalf).toString();
179        }
180}