1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /** 19 * @author Vladimir N. Molotkov 20 * @version $Revision$ 21 */ 22 23 package org.apache.harmony.security.utils; 24 25 import java.security.Provider; 26 import java.security.Security; 27 import java.util.HashMap; 28 import java.util.Locale; 29 import java.util.Map; 30 import java.util.Map.Entry; 31 import java.util.Set; 32 import org.apache.harmony.security.asn1.ObjectIdentifier; 33 import org.apache.harmony.security.fortress.Services; 34 35 /** 36 * Provides Algorithm Name to OID and OID to Algorithm Name mappings. Some known 37 * mappings are hardcoded. Tries to obtain additional mappings from installed 38 * providers during initialization. 39 */ 40 public class AlgNameMapper { 41 private static AlgNameMapperSource source = null; 42 43 private static volatile int cacheVersion = -1; 44 45 // Will search OID mappings for these services 46 private static final String[] serviceName = { 47 "Cipher", 48 "AlgorithmParameters", 49 "Signature" 50 }; 51 52 // These mappings CAN NOT be overridden 53 // by the ones from available providers 54 // during maps initialization 55 // (source: http://asn1.elibel.tm.fr): 56 private static final String[][] knownAlgMappings = { 57 {"1.2.840.10040.4.1", "DSA"}, 58 {"1.2.840.10040.4.3", "SHA1withDSA"}, 59 {"1.2.840.113549.1.1.1", "RSA"}, 60 // BEGIN android-removed 61 // Dropping MD2 62 // {"1.2.840.113549.1.1.2", "MD2withRSA"}, 63 // END android-removed 64 {"1.2.840.113549.1.1.4", "MD5withRSA"}, 65 {"1.2.840.113549.1.1.5", "SHA1withRSA"}, 66 {"1.2.840.113549.1.3.1", "DiffieHellman"}, 67 {"1.2.840.113549.1.5.3", "pbeWithMD5AndDES-CBC"}, 68 {"1.2.840.113549.1.12.1.3", "pbeWithSHAAnd3-KeyTripleDES-CBC"}, 69 {"1.2.840.113549.1.12.1.6", "pbeWithSHAAnd40BitRC2-CBC"}, 70 {"1.2.840.113549.3.2", "RC2-CBC"}, 71 {"1.2.840.113549.3.3", "RC2-EBC"}, 72 {"1.2.840.113549.3.4", "RC4"}, 73 {"1.2.840.113549.3.5", "RC4WithMAC"}, 74 {"1.2.840.113549.3.6", "DESx-CBC"}, 75 {"1.2.840.113549.3.7", "TripleDES-CBC"}, 76 {"1.2.840.113549.3.8", "rc5CBC"}, 77 {"1.2.840.113549.3.9", "RC5-CBC"}, 78 {"1.2.840.113549.3.10", "DESCDMF"}, 79 {"2.23.42.9.11.4.1", "ECDSA"}, 80 }; 81 // Maps alg name to OID 82 private static final Map<String, String> alg2OidMap = new HashMap<String, String>(); 83 // Maps OID to alg name 84 private static final Map<String, String> oid2AlgMap = new HashMap<String, String>(); 85 // Maps aliases to alg names 86 private static final Map<String, String> algAliasesMap = new HashMap<String, String>(); 87 88 static { 89 for (String[] element : knownAlgMappings) { 90 String algUC = element[1].toUpperCase(Locale.US); 91 alg2OidMap.put(algUC, element[0]); 92 oid2AlgMap.put(element[0], algUC); 93 // map upper case alg name to its original name 94 algAliasesMap.put(algUC, element[1]); 95 } 96 } 97 98 // No instances 99 private AlgNameMapper() { 100 } 101 102 private static synchronized void checkCacheVersion() { 103 int newCacheVersion = Services.getCacheVersion(); 104 if (newCacheVersion != cacheVersion) { 105 // 106 // Now search providers for mappings like 107 // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name> 108 // or 109 // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name> 110 // 111 Provider[] pl = Security.getProviders(); 112 for (Provider element : pl) { 113 selectEntries(element); 114 } 115 cacheVersion = newCacheVersion; 116 } 117 } 118 119 /** 120 * Returns OID for algName 121 * 122 * @param algName algorithm name to be mapped 123 * @return OID as String 124 */ 125 public static String map2OID(String algName) { 126 checkCacheVersion(); 127 128 // alg2OidMap map contains upper case keys 129 String result = alg2OidMap.get(algName.toUpperCase(Locale.US)); 130 if (result != null) { 131 return result; 132 } 133 134 // Check our external source. 135 AlgNameMapperSource s = source; 136 if (s != null) { 137 return s.mapNameToOid(algName); 138 } 139 140 return null; 141 } 142 143 /** 144 * Returns algName for OID 145 * 146 * @param oid OID to be mapped 147 * @return algorithm name 148 */ 149 public static String map2AlgName(String oid) { 150 checkCacheVersion(); 151 152 // oid2AlgMap map contains upper case values 153 String algUC = oid2AlgMap.get(oid); 154 // if not null there is always map UC->Orig 155 if (algUC != null) { 156 return algAliasesMap.get(algUC); 157 } 158 159 // Check our external source. 160 AlgNameMapperSource s = source; 161 if (s != null) { 162 return s.mapOidToName(oid); 163 } 164 165 return null; 166 } 167 168 /** 169 * Returns Algorithm name for given algorithm alias 170 * 171 * @param algName - alias 172 * @return algorithm name 173 */ 174 public static String getStandardName(String algName) { 175 return algAliasesMap.get(algName.toUpperCase(Locale.US)); 176 } 177 178 // Searches given provider for mappings like 179 // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name> 180 // or 181 // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name> 182 // Puts mappings found into appropriate internal maps 183 private static void selectEntries(Provider p) { 184 Set<Map.Entry<Object, Object>> entrySet = p.entrySet(); 185 for (String service : serviceName) { 186 String keyPrfix2find = "Alg.Alias." + service + "."; 187 for (Entry<Object, Object> me : entrySet) { 188 String key = (String)me.getKey(); 189 if (key.startsWith(keyPrfix2find)) { 190 String alias = key.substring(keyPrfix2find.length()); 191 String alg = (String)me.getValue(); 192 String algUC = alg.toUpperCase(Locale.US); 193 if (isOID(alias)) { 194 if (alias.startsWith("OID.")) { 195 alias = alias.substring(4); 196 } 197 // Do not overwrite already known mappings 198 boolean oid2AlgContains = oid2AlgMap.containsKey(alias); 199 boolean alg2OidContains = alg2OidMap.containsKey(algUC); 200 if (!oid2AlgContains || !alg2OidContains) { 201 if (!oid2AlgContains) { 202 oid2AlgMap.put(alias, algUC); 203 } 204 if (!alg2OidContains) { 205 alg2OidMap.put(algUC, alias); 206 } 207 // map upper case alg name to its original name 208 algAliasesMap.put(algUC, alg); 209 } 210 // Do not override known standard names 211 } else if (!algAliasesMap.containsKey(alias.toUpperCase(Locale.US))) { 212 algAliasesMap.put(alias.toUpperCase(Locale.US), alg); 213 } 214 } 215 } 216 } 217 } 218 219 /** 220 * Checks if parameter represents OID 221 * 222 * @param alias alias to be checked 223 * @return 'true' if parameter represents OID 224 */ 225 public static boolean isOID(String alias) { 226 return ObjectIdentifier.isOID(normalize(alias)); 227 } 228 229 /** 230 * Removes leading "OID." from oid String passed 231 * 232 * @param oid string that may contain leading "OID." 233 * @return string passed without leading "OID." 234 */ 235 public static String normalize(String oid) { 236 return oid.startsWith("OID.") 237 ? oid.substring(4) 238 : oid; 239 } 240 241 public static void setSource(AlgNameMapperSource source) { 242 AlgNameMapper.source = source; 243 } 244 } 245