001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.security;
020
021import java.io.IOException;
022import java.io.InputStream;
023import java.util.Collections;
024import java.util.LinkedHashMap;
025import java.util.Map;
026import java.util.Properties;
027
028/**
029 * Defines the primary usage of the key contained in the key block.
030 * <p>
031 * Each value repesents bytes 5-6 of the Keyblok Header.
032 * <p>
033 * This class defines proprietary specific key usages. In the great majority of
034 * cases, the ones defined by TR-31 {@link KeyUsage} will be sufficient. There
035 * are no strong reasons for separating e.g. KEK keys to ZMK and TMK, or PINENC
036 * keys to ZPK and TPK. KEK and PINENC should be enough.
037 * <p>
038 * However, when it is necessary to use, for example: private/public RSA keys
039 * or HMAC keys, the only option is to use the proprietary key usages.
040 * <p>
041 * The proprietary key usages for {@code ExtKeyUsage} are optional and can be
042 * defined in your resources at {@value ExtKeyUsage#EXTERNAL_KEY_USAGES}. A file
043 * with the same name in the jPOS test resources can be used as an example.
044 */
045public class ExtKeyUsage extends KeyUsage {
046
047    /**
048     * Key usages by code key.
049     * <p>
050     * This field has to be first
051     */
052    private static final Map<String, KeyUsage> MAP = new LinkedHashMap<>();
053
054    private static final String EXTERNAL_KEY_USAGES = "META-INF/org/jpos/security/proprietary-hsm.properties";
055
056    private static final String KEY_USAGE_PREFIX    = "ku.";
057
058    /**
059     * Key usages by entry key.
060     * <p>
061     * This field has to be after {@link MAP} and before key usages;
062     */
063    private static final Map<String, KeyUsage> EXT_DEF = loadKeyUsagesFromClasspath(EXTERNAL_KEY_USAGES);
064
065    /**
066     * DEK - Data Encryption Key.
067     *
068     * @apiNote It is proprietary specific version of {@link KeyUsage#ENC}
069     */
070    public final static KeyUsage DEK        = getKeyUsage("DEK");
071
072    /**
073     * ZEK - Zone Encryption Key.
074     *
075     * @apiNote It is proprietary specific version of {@link KeyUsage#ENC}
076     */
077    public final static KeyUsage ZEK        = getKeyUsage("ZEK");
078
079    /**
080     * TEK - Terminal Encryption Key.
081     *
082     * @apiNote It is proprietary specific version of {@link KeyUsage#ENC}
083     */
084    public final static KeyUsage TEK        = getKeyUsage("TEK");
085
086    /**
087     * RSA Public Key.
088     *
089     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
090     */
091    public final static KeyUsage RSAPK      = getKeyUsage("RSAPK");
092
093    /**
094     * RSA Private Key for signing or key management.
095     *
096     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
097     */
098    public final static KeyUsage RSASK      = getKeyUsage("RSASK");
099
100    /**
101     * RSA Private Key for ICC personalization.
102     *
103     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
104     */
105    public final static KeyUsage RSASKICC   = getKeyUsage("RSASKICC");
106
107    /**
108     * RSA Private Key for PIN translation.
109     *
110     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
111     */
112    public final static KeyUsage RSASKPIN   = getKeyUsage("RSASKPIN");
113
114    /**
115     * RSA Private Key for TLS.
116     *
117     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
118     */
119    public final static KeyUsage RSASKTLS   = getKeyUsage("RSASKTLS");
120
121    /**
122     * TMK - Terminal Master Key.
123     *
124     * @apiNote It is proprietary specific version of {@link KeyUsage#KEK}
125     */
126    public final static KeyUsage TMK        = getKeyUsage("TMK");
127
128    /**
129     * ZMK - Zone Master Key.
130     *
131     * @apiNote It is proprietary specific version of {@link KeyUsage#KEK}
132     */
133    public final static KeyUsage ZMK        = getKeyUsage("ZMK");
134
135    /**
136     * HMAC key using SHA-1.
137     *
138     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
139     */
140    public final static KeyUsage HMACSHA1   = getKeyUsage("HMACSHA1");
141
142    /**
143     * HMAC key using SHA-224.
144     *
145     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
146     */
147    public final static KeyUsage HMACSHA224 = getKeyUsage("HMACSHA224");
148
149    /**
150     * HMAC key using SHA-256.
151     *
152     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
153     */
154    public final static KeyUsage HMACSHA256 = getKeyUsage("HMACSHA256");
155
156    /**
157     * HMAC key using SHA-384.
158     *
159     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
160     */
161    public final static KeyUsage HMACSHA384 = getKeyUsage("HMACSHA384");
162
163    /**
164     * HMAC key using SHA-512.
165     *
166     * @apiNote It is proprietary specific, there is no equivalent in TR-31.
167     */
168    public final static KeyUsage HMACSHA512 = getKeyUsage("HMACSHA512");
169
170    /**
171     * TPK - Terminal PIN Encryption Key.
172     *
173     * @apiNote It is proprietary specific version of {@link KeyUsage#PINENC}
174     */
175    public final static KeyUsage TPK        = getKeyUsage("TPK");
176
177    /**
178     * ZPK - Zone PIN Encryption Key.
179     *
180     * @apiNote It is proprietary specific version of {@link KeyUsage#PINENC}
181     */
182    public final static KeyUsage ZPK        = getKeyUsage("ZPK");
183
184
185    /**
186     * Internal constructor.
187     * <p>
188     * The constructor is protected to guarantee only one instance of the key
189     * usage in the entire JVM. This makes it possible to use the operator
190     * {@code ==} or {@code !=} as it does for enums.
191     *
192     * @param code the key usage code
193     * @param name the usage name
194     */
195    protected ExtKeyUsage(String code, String name) {
196        super(code, name);
197    }
198
199    private static KeyUsage getKeyUsage(String entry) {
200        if (EXT_DEF == null)
201            return null;
202
203        return EXT_DEF.get(entry);
204    }
205
206    /**
207     * Returns the enum constant of this type with the specified {@code code}.
208     *
209     * @param code
210     * @return the enum constant with the specified processing code or
211     *         {@code null} if unknown.
212     */
213    public static KeyUsage valueOfByCode(String code) {
214        KeyUsage ku = MAP.get(code);
215        if (ku != null)
216            return ku;
217
218        return TR31MAP.get(code);
219    }
220
221    public static Map<String, KeyUsage> entries() {
222        Map ret = new LinkedHashMap(TR31MAP);
223        ret.putAll(MAP);
224        return Collections.unmodifiableMap(ret);
225    }
226
227    private static InputStream loadResourceAsStream(String name) {
228        InputStream in = null;
229
230        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
231        if (contextClassLoader != null)
232            in = contextClassLoader.getResourceAsStream(name);
233
234        if (in == null)
235            in = ExtKeyUsage.class.getClassLoader().getResourceAsStream(name);
236
237        return in;
238    }
239
240    static Map<String, KeyUsage> loadKeyUsagesFromClasspath(String resource) {
241        Properties props = new Properties();
242        try (InputStream in = loadResourceAsStream(resource)) {
243            props.load(in);
244            return registerKeyUsages(props);
245        } catch (IOException | NullPointerException ex) {
246            return null;
247        }
248    }
249
250    private static Map<String, KeyUsage> registerKeyUsages(Properties props) {
251        Map<String, KeyUsage> ret = new LinkedHashMap<>();
252        for (String key : props.stringPropertyNames()) {
253            if (!key.startsWith(KEY_USAGE_PREFIX))
254                continue;
255
256            String value = props.getProperty(key);
257            if (value == null || value.isEmpty())
258                continue;
259
260            String k = key.substring(KEY_USAGE_PREFIX.length());
261            String[] entry = value.split(",");
262            KeyUsage ku = new KeyUsage(entry[0], entry[1]);
263            // Override is disabled
264            if (MAP.containsKey(ku.getCode()))
265                continue;
266
267            ret.put(k, ku);
268            MAP.put(ku.getCode(), ku);
269        }
270
271        return ret;
272    }
273
274}