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.oauth2.sdk.auth;
019
020
021import java.security.cert.X509Certificate;
022import java.text.ParseException;
023import java.util.AbstractMap;
024import java.util.Map;
025import java.util.Objects;
026
027import com.nimbusds.jose.util.Base64URL;
028import com.nimbusds.jose.util.JSONObjectUtils;
029import com.nimbusds.jose.util.X509CertUtils;
030import com.nimbusds.jwt.JWTClaimsSet;
031import net.jcip.annotations.Immutable;
032import net.minidev.json.JSONObject;
033
034
035/**
036 * X.509 certificate SHA-256 confirmation.
037 */
038@Immutable
039public final class X509CertificateConfirmation {
040        
041        
042        /**
043         * The X.509 certificate SHA-256 thumbprint.
044         */
045        private final Base64URL x5tS256;
046        
047        
048        /**
049         * Creates a new X.509 certificate SHA-256 confirmation.
050         *
051         * @param x5tS256 The X.509 certificate SHA-256 thumbprint. Must not
052         *                be {@code null}.
053         */
054        public X509CertificateConfirmation(final Base64URL x5tS256) {
055                
056                if (x5tS256 == null) {
057                        throw new IllegalArgumentException("The X.509 certificate thumbprint must not be null");
058                }
059                
060                this.x5tS256 = x5tS256;
061        }
062        
063        
064        /**
065         * Returns the X.509 certificate SHA-256 thumbprint.
066         *
067         * @return The X.509 certificate SHA-256 thumbprint.
068         */
069        public Base64URL getValue() {
070                
071                return x5tS256;
072        }
073        
074        
075        /**
076         * Returns this X.509 certificate SHA-256 confirmation as a JSON
077         * object.
078         *
079         * <p>Example:
080         *
081         * <pre>
082         * {
083         *   "cnf" : { "x5t#S256" : "bwcK0esc3ACC3DB2Y5_lESsXE8o9ltc05O89jdN-dg2" }
084         * }
085         * </pre>
086         *
087         * @return The JSON object.
088         */
089        public JSONObject toJSONObject() {
090                
091                JSONObject jsonObject = new JSONObject();
092                Map.Entry<String, JSONObject> cnfClaim = toJWTClaim();
093                jsonObject.put(cnfClaim.getKey(), cnfClaim.getValue());
094                return jsonObject;
095        }
096        
097        
098        /**
099         * Returns this X.509 certificate SHA-256 confirmation as a JWT claim.
100         *
101         * <p>Example:
102         *
103         * <pre>
104         * "cnf" : { "x5t#S256" : "bwcK0esc3ACC3DB2Y5_lESsXE8o9ltc05O89jdN-dg2" }
105         * </pre>
106         *
107         * @return The JWT claim name / value.
108         */
109        public Map.Entry<String,JSONObject> toJWTClaim() {
110                
111                JSONObject cnf = new JSONObject();
112                cnf.put("x5t#S256", x5tS256.toString());
113                
114                return new AbstractMap.SimpleImmutableEntry<>(
115                        "cnf",
116                        cnf
117                );
118        }
119        
120        
121        /**
122         * Applies this X.509 certificate SHA-256 confirmation to the specified
123         * JWT claims set.
124         *
125         * @param jwtClaimsSet The JWT claims set.
126         *
127         * @return The modified JWT claims set.
128         */
129        public JWTClaimsSet applyTo(final JWTClaimsSet jwtClaimsSet) {
130                
131                Map.Entry<String, JSONObject> cnfClaim = toJWTClaim();
132                
133                return new JWTClaimsSet.Builder(jwtClaimsSet)
134                        .claim(cnfClaim.getKey(), cnfClaim.getValue())
135                        .build();
136        }
137        
138        
139        @Override
140        public String toString() {
141                return toJSONObject().toJSONString();
142        }
143        
144        
145        @Override
146        public boolean equals(Object o) {
147                if (this == o) return true;
148                if (!(o instanceof X509CertificateConfirmation)) return false;
149                X509CertificateConfirmation that = (X509CertificateConfirmation) o;
150                return x5tS256.equals(that.x5tS256);
151        }
152        
153        
154        @Override
155        public int hashCode() {
156                return Objects.hash(x5tS256);
157        }
158        
159        
160        /**
161         * Parses a X.509 certificate confirmation from the specified JWT
162         * claims set.
163         *
164         * @param jwtClaimsSet The JWT claims set.
165         *
166         * @return The X.509 certificate confirmation, {@code null} if not
167         *         found.
168         */
169        public static X509CertificateConfirmation parse(final JWTClaimsSet jwtClaimsSet) {
170                
171                JSONObject cnf;
172                try {
173                        cnf = jwtClaimsSet.getJSONObjectClaim("cnf");
174                } catch (ParseException e) {
175                        return null;
176                }
177                
178                return parseFromConfirmationJSONObject(cnf);
179        }
180        
181        
182        /**
183         * Parses a X.509 certificate confirmation from the specified JSON
184         * object representation of a JWT claims set.
185         *
186         * @param jsonObject The JSON object.
187         *
188         * @return The X.509 certificate confirmation, {@code null} if not
189         *         found.
190         */
191        public static X509CertificateConfirmation parse(final JSONObject jsonObject) {
192                
193                if (! jsonObject.containsKey("cnf")) {
194                        return null;
195                }
196                
197                try {
198                        return parseFromConfirmationJSONObject(JSONObjectUtils.getJSONObject(jsonObject, "cnf"));
199                } catch (ParseException e) {
200                        return null;
201                }
202        }
203        
204        
205        /**
206         * Parses a X.509 certificate confirmation from the specified
207         * confirmation ("cnf") JSON object.
208         *
209         * @param cnf The confirmation JSON object, {@code null} if none.
210         *
211         * @return The X.509 certificate confirmation, {@code null} if not
212         *         found.
213         */
214        public static X509CertificateConfirmation parseFromConfirmationJSONObject(final JSONObject cnf) {
215                
216                if (cnf == null) {
217                        return null;
218                }
219                
220                try {
221                        String x5tString = JSONObjectUtils.getString(cnf, "x5t#S256");
222                        
223                        if (x5tString == null) {
224                                return null;
225                        }
226                        
227                        return new X509CertificateConfirmation(new Base64URL(x5tString));
228                        
229                } catch (ParseException e) {
230                        return null;
231                }
232        }
233        
234        
235        /**
236         * Creates a confirmation of the specified X.509 certificate.
237         *
238         * @param x509Cert The X.509 certificate.
239         *
240         * @return The X.509 certificate confirmation.
241         */
242        public static X509CertificateConfirmation of(final X509Certificate x509Cert) {
243                
244                return new X509CertificateConfirmation(X509CertUtils.computeSHA256Thumbprint(x509Cert));
245        }
246}