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}