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.xnet.provider.jsse.NativeCrypto; 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 42 // Will search OID mappings for these services 43 private static final String[] serviceName = { 44 "Cipher", 45 "AlgorithmParameters", 46 "Signature" 47 }; 48 49 // These mappings CAN NOT be overridden 50 // by the ones from available providers 51 // during maps initialization 52 // (source: http://asn1.elibel.tm.fr): 53 private static final String[][] knownAlgMappings = { 54 {"1.2.840.10040.4.1", "DSA"}, 55 {"1.2.840.10040.4.3", "SHA1withDSA"}, 56 {"1.2.840.113549.1.1.1", "RSA"}, 57 // BEGIN android-removed 58 // Dropping MD2 59 // {"1.2.840.113549.1.1.2", "MD2withRSA"}, 60 // END android-removed 61 {"1.2.840.113549.1.1.4", "MD5withRSA"}, 62 {"1.2.840.113549.1.1.5", "SHA1withRSA"}, 63 {"1.2.840.113549.1.3.1", "DiffieHellman"}, 64 {"1.2.840.113549.1.5.3", "pbeWithMD5AndDES-CBC"}, 65 {"1.2.840.113549.1.12.1.3", "pbeWithSHAAnd3-KeyTripleDES-CBC"}, 66 {"1.2.840.113549.1.12.1.6", "pbeWithSHAAnd40BitRC2-CBC"}, 67 {"1.2.840.113549.3.2", "RC2-CBC"}, 68 {"1.2.840.113549.3.3", "RC2-EBC"}, 69 {"1.2.840.113549.3.4", "RC4"}, 70 {"1.2.840.113549.3.5", "RC4WithMAC"}, 71 {"1.2.840.113549.3.6", "DESx-CBC"}, 72 {"1.2.840.113549.3.7", "TripleDES-CBC"}, 73 {"1.2.840.113549.3.8", "rc5CBC"}, 74 {"1.2.840.113549.3.9", "RC5-CBC"}, 75 {"1.2.840.113549.3.10", "DESCDMF"}, 76 {"2.23.42.9.11.4.1", "ECDSA"}, 77 }; 78 // Maps alg name to OID 79 private static final Map<String, String> alg2OidMap = new HashMap<String, String>(); 80 // Maps OID to alg name 81 private static final Map<String, String> oid2AlgMap = new HashMap<String, String>(); 82 // Maps aliases to alg names 83 private static final Map<String, String> algAliasesMap = new HashMap<String, String>(); 84 85 static { 86 for (String[] element : knownAlgMappings) { 87 String algUC = element[1].toUpperCase(Locale.US); 88 alg2OidMap.put(algUC, element[0]); 89 oid2AlgMap.put(element[0], algUC); 90 // map upper case alg name to its original name 91 algAliasesMap.put(algUC, element[1]); 92 } 93 // 94 // Now search providers for mappings like 95 // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name> 96 // or 97 // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name> 98 // 99 Provider[] pl = Security.getProviders(); 100 for (Provider element : pl) { 101 selectEntries(element); 102 } 103 } 104 105 // No instances 106 private AlgNameMapper() { 107 } 108 109 /** 110 * Returns OID for algName 111 * 112 * @param algName algorithm name to be mapped 113 * @return OID as String 114 */ 115 public static String map2OID(String algName) { 116 // alg2OidMap map contains upper case keys 117 final String result = alg2OidMap.get(algName.toUpperCase(Locale.US)); 118 if (result != null) { 119 return result; 120 } 121 122 return NativeCrypto.OBJ_txt2nid_oid(algName); 123 } 124 125 /** 126 * Returns algName for OID 127 * 128 * @param oid OID to be mapped 129 * @return algorithm name 130 */ 131 public static String map2AlgName(String oid) { 132 // oid2AlgMap map contains upper case values 133 String algUC = oid2AlgMap.get(oid); 134 // if not null there is always map UC->Orig 135 if (algUC != null) { 136 return algAliasesMap.get(algUC); 137 } 138 139 // If we don't know about this OID, ask OpenSSL if it does. 140 return NativeCrypto.OBJ_txt2nid_longName(oid); 141 } 142 143 /** 144 * Returns Algorithm name for given algorithm alias 145 * 146 * @param algName - alias 147 * @return algorithm name 148 */ 149 public static String getStandardName(String algName) { 150 return algAliasesMap.get(algName.toUpperCase(Locale.US)); 151 } 152 153 // Searches given provider for mappings like 154 // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name> 155 // or 156 // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name> 157 // Puts mappings found into appropriate internal maps 158 private static void selectEntries(Provider p) { 159 Set<Map.Entry<Object, Object>> entrySet = p.entrySet(); 160 for (String service : serviceName) { 161 String keyPrfix2find = "Alg.Alias." + service + "."; 162 for (Entry<Object, Object> me : entrySet) { 163 String key = (String)me.getKey(); 164 if (key.startsWith(keyPrfix2find)) { 165 String alias = key.substring(keyPrfix2find.length()); 166 String alg = (String)me.getValue(); 167 String algUC = alg.toUpperCase(Locale.US); 168 if (isOID(alias)) { 169 if (alias.startsWith("OID.")) { 170 alias = alias.substring(4); 171 } 172 // Do not overwrite already known mappings 173 boolean oid2AlgContains = oid2AlgMap.containsKey(alias); 174 boolean alg2OidContains = alg2OidMap.containsKey(algUC); 175 if (!oid2AlgContains || !alg2OidContains) { 176 if (!oid2AlgContains) { 177 oid2AlgMap.put(alias, algUC); 178 } 179 if (!alg2OidContains) { 180 alg2OidMap.put(algUC, alias); 181 } 182 // map upper case alg name to its original name 183 algAliasesMap.put(algUC, alg); 184 } 185 // Do not override known standard names 186 } else if (!algAliasesMap.containsKey(alias.toUpperCase(Locale.US))) { 187 algAliasesMap.put(alias.toUpperCase(Locale.US), alg); 188 } 189 } 190 } 191 } 192 } 193 194 /** 195 * Checks if parameter represents OID 196 * 197 * @param alias alias to be checked 198 * @return 'true' if parameter represents OID 199 */ 200 public static boolean isOID(String alias) { 201 return ObjectIdentifier.isOID(normalize(alias)); 202 } 203 204 /** 205 * Removes leading "OID." from oid String passed 206 * 207 * @param oid string that may contain leading "OID." 208 * @return string passed without leading "OID." 209 */ 210 public static String normalize(String oid) { 211 return oid.startsWith("OID.") 212 ? oid.substring(4) 213 : oid; 214 } 215 } 216