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