001package com.nimbusds.jose.jwk;
002
003
004import java.io.Serializable;
005import java.security.Key;
006
007import com.nimbusds.jose.Algorithm;
008import com.nimbusds.jose.JWEAlgorithm;
009import com.nimbusds.jose.JWSAlgorithm;
010import net.jcip.annotations.Immutable;
011
012import net.minidev.json.JSONAware;
013import net.minidev.json.JSONObject;
014
015import com.nimbusds.jose.Requirement;
016
017
018/**
019 * Key type. Represents the {@code kty} parameter in a JSON Web Key (JWK). 
020 * This class is immutable.
021 *
022 * <p>Includes constants for the following standard key types:
023 *
024 * <ul>
025 *     <li>{@link #EC}
026 *     <li>{@link #RSA}
027 *     <li>{@link #OCT}
028 * </ul>
029 *
030 * <p>Additional key types can be defined using the constructor.
031 *
032 * @author Vladimir Dzhuvinov
033 * @author Justin Richer
034 * @version 2015-11-30
035 */
036@Immutable
037public final class KeyType implements JSONAware, Serializable {
038
039
040        private static final long serialVersionUID = 1L;
041
042
043        /**
044         * The key type value.
045         */
046        private final String value;
047
048
049        /**
050         * The implementation requirement, {@code null} if not known.
051         */
052        private final Requirement requirement;
053
054
055        /**
056         * Elliptic Curve (DSS) key type (recommended).
057         */
058        public static final KeyType EC = new KeyType("EC", Requirement.RECOMMENDED);
059
060
061        /**
062         * RSA (RFC 3447) key type (required).
063         */
064        public static final KeyType RSA = new KeyType("RSA", Requirement.REQUIRED);
065
066
067        /**
068         * Octet sequence key type (optional)
069         */
070        public static final KeyType OCT = new KeyType("oct", Requirement.OPTIONAL);
071        
072
073        /**
074         * Creates a new key type with the specified value and implementation 
075         * requirement.
076         *
077         * @param value The key type value. Values are case sensitive. Must not
078         *              be {@code null}.
079         * @param req   The implementation requirement, {@code null} if not 
080         *              known.
081         */
082        public KeyType(final String value, final Requirement req) {
083
084                if (value == null) {
085
086                        throw new IllegalArgumentException("The key type value must not be null");
087                }
088
089                this.value = value;
090
091                requirement = req;
092        }
093
094
095        /**
096         * Gets the value of this key type. Values are case sensitive.
097         *
098         * @return The key type.
099         */
100        public String getValue() {
101
102                return value;
103        }
104
105
106        /**
107         * Gets the implementation requirement of this key type.
108         *
109         * @return The implementation requirement, {@code null} if not known.
110         */
111        public Requirement getRequirement() {
112
113                return requirement;
114        }
115
116
117        /**
118         * Overrides {@code Object.hashCode()}.
119         *
120         * @return The object hash code.
121         */
122        @Override
123        public int hashCode() {
124
125                return value.hashCode();
126        }
127
128
129        /**
130         * Overrides {@code Object.equals()}.
131         *
132         * @param object The object to compare to.
133         *
134         * @return {@code true} if the objects have the same value, otherwise
135         *         {@code false}.
136         */
137        @Override
138        public boolean equals(final Object object) {
139
140                return object != null && 
141                       object instanceof KeyType && 
142                       this.toString().equals(object.toString());
143        }
144
145
146        /**
147         * Returns the string representation of this key type.
148         *
149         * @see #getValue
150         *
151         * @return The string representation.
152         */
153        @Override
154        public String toString() {
155
156                return value;
157        }
158
159
160        /**
161         * Returns the JSON string representation of this key type.
162         * 
163         * @return The JSON string representation.
164         */
165        @Override
166        public String toJSONString() {
167
168                return "\"" + JSONObject.escape(value) + '"';
169        }
170
171
172        /**
173         * Parses a key type from the specified {@code kty} parameter value.
174         *
175         * @param s The string to parse. Must not be {@code null}.
176         *
177         * @return The key type (matching standard key type constant, else a 
178         *         newly created one).
179         */
180        public static KeyType parse(final String s) {
181
182                if (s.equals(EC.getValue())) {
183
184                        return EC;
185
186                } else if (s.equals(RSA.getValue())) {
187
188                        return RSA;
189
190                } else if (s.equals(OCT.getValue())) {
191
192                        return OCT;
193
194                } else {
195                        
196                        return new KeyType(s, null);
197                }
198        }
199
200
201        /**
202         * Infers the key type for the specified JOSE algorithm.
203         *
204         * @param alg The JOSE algorithm. May be {@code null}.
205         *
206         * @return The key type, {@code null} if it couldn't be inferred.
207         */
208        public static KeyType forAlgorithm(final Algorithm alg) {
209
210                if (alg == null) {
211                        return null;
212                }
213
214                if (JWSAlgorithm.Family.RSA.contains(alg)) {
215                        return KeyType.RSA;
216                } else if (JWSAlgorithm.Family.EC.contains(alg)) {
217                        return KeyType.EC;
218                } else if (JWSAlgorithm.Family.HMAC_SHA.contains(alg)) {
219                        return KeyType.OCT;
220                } else if (JWEAlgorithm.Family.RSA.contains(alg)) {
221                        return KeyType.RSA;
222                } else if (JWEAlgorithm.Family.ECDH_ES.contains(alg)) {
223                        return KeyType.EC;
224                } else if (JWEAlgorithm.DIR.equals(alg)) {
225                        return KeyType.OCT;
226                } else if (JWEAlgorithm.Family.AES_GCM_KW.contains(alg)) {
227                        return KeyType.OCT;
228                } else if (JWEAlgorithm.Family.AES_KW.contains(alg)) {
229                        return KeyType.OCT;
230                } else if (JWEAlgorithm.Family.PBES2.contains(alg)) {
231                        return KeyType.OCT;
232                } else {
233                        return null;
234                }
235        }
236}